生活随笔
收集整理的這篇文章主要介紹了
【hdu4281状态压缩+01背包+多旅行商问题】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意:有n道題,每道題在二維平面內(nèi)的不同位置且給出每道題的坐標(biāo),同時(shí)給出處理每道題所需的時(shí)間p,現(xiàn)在已知裁判的耐心有限,之會(huì)花費(fèi)m個(gè)單位時(shí)間去做事,做完后回到起始點(diǎn)。
現(xiàn)在的要求是,我要多少個(gè)裁判才能對(duì)每個(gè)問題都處理完,并且同一道題不能有兩個(gè)裁判進(jìn)行處理,并求出總路徑最小的值。
總復(fù)雜度O(2^(2*n)+(2^n*n^2))
#include <bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include <iostream>
#include <cstring>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define MIN (1<<17)
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
int greedy();
int TSP_SECOND();
int n,m;
int tot;//總的合法物品數(shù)
int ans1;//第一問答案
int ans2;//第二問答案
int x[20],y[20];//坐標(biāo)
int val[20];//權(quán)花費(fèi)的時(shí)間
int dp[MIN],state[MIN];//求最少多少個(gè)教練
int mp[20][20],isok[MIN];//邊權(quán)、合法物品集合
int cost[17][MIN],np[MIN];//多旅行商問題用到
void init()
{tot=0;//memset(map,0,sizeof(map));for(int i=0;i<(1<<n);++i) np[i]=inf;///for(int i=0;i<=n;++i)for(int j=0;j<(1<<n);++j)cost[i][j]=inf;cost[0][1]=0;}
int Enumeration_subset(int x)
{int sum=0;for(int i=0;i<n;++i)//所在的集合iif(x&(1<<i))sum+=val[i];return sum<=m;
}
//將2^n種地點(diǎn)的選擇集合壓縮成2^n個(gè)物品(2^n個(gè)狀態(tài),因?yàn)槊總€(gè)任務(wù)在一個(gè)教練的下有被選擇和不被選擇兩種狀態(tài)),物品的權(quán)值為集合內(nèi)的點(diǎn)權(quán)之和,
//如果總和<=m,那么他是一種合法的組合(說明是一個(gè)裁判可以在m的范圍內(nèi)可以把這些任務(wù)完成),存起來。
//這樣就得到tot種合法組合,對(duì)這tot種組合進(jìn)行01背包(注意是對(duì)合法的組合進(jìn)行01背包),dp[i]表示容量為i時(shí)的最小費(fèi)用(轉(zhuǎn)化為對(duì)應(yīng)得前i個(gè)二進(jìn)制位位1得狀態(tài)所需要的教練數(shù)),和常規(guī)的背包不同(但本質(zhì)是一樣的。)
//狀態(tài)轉(zhuǎn)移方程:dp[i] = min(dp[i],dp[j]+1)
//(j為i的子集(注意j是i的子集),i = j | state[k]并且j和state[k]沒有交集,state[k]表示第k個(gè)合法物品)
int DP_FIRST()
{//int mmin=inf;for(int i=0;i<(1<<n);++i) dp[i]=inf;dp[0]=0;for(int i=0;i<tot;++i){for(int j=(1<<n)-1;j>=0;--j){if(dp[j]==inf)continue;if((j+state[i])!=(j|state[i]))continue;//兩種狀態(tài)不能有交集 也可寫成if((j&state[i])!=0) 在poj2923中可以看到dp[j+state[i]]=min(dp[j+state[i]],dp[j]+1);//}}return dp[(1<<n)-1];
}
int main()
{while(cin>>n>>m){init();for(int i=0;i<n;++i)cin>>x[i]>>y[i];for(int i=0;i<n;++i)cin>>val[i];for(int i=1;i<(1<<n);++i){isok[i]=Enumeration_subset(i);if(isok[i])state[tot++]=i;}ans1=DP_FIRST(); //狀態(tài)壓縮01背包去求最少多少個(gè)教練//ans1=greedy(); //greedy求解if(ans1==inf){cout<<-1<<' '<<-1<<endl;continue;}//不能完成所有的任務(wù)ans2=TSP_SECOND();cout<<ans1<<' '<<ans2<<endl;}return 0;
}
/*
貪心得思想去求解最少要用多少個(gè)教練的個(gè)數(shù),每次一個(gè)教練都是從任務(wù)花費(fèi)的時(shí)間最大的時(shí)候開始進(jìn)行計(jì)算,直到不能解決新的任務(wù)結(jié)束
之后在對(duì)下一個(gè)教練進(jìn)行op,
*/
int greedy()
{int temp[20],vis[20];for(int i=0;i<n;++i)temp[i]=val[i],vis[i]=0;sort(temp,temp);for(int i=1;i<=n;++i){int rest=m;for(int j=n-1;j>=0;--j)if(!vis[j]&&temp[j]<=rest)rest-=temp[j],vis[j]=1;for(int j=n-1;j>=0&&vis[j]==1;--j){if(j==0)return i;}}return inf;
}
/*
第二問:多旅行商問題即mTsp,感覺挺經(jīng)典的,思路是將mtsp轉(zhuǎn)化成普通的tsp,然后再將各個(gè)tsp合并成答案。
先要O(2^n*n^2)的預(yù)處理得到np[i]表示一個(gè)裁判走的集合為i的所有地點(diǎn)又回到最初的點(diǎn)的最少權(quán)值和,
然后np[i] = min(np[i],np[k|(1<<0)]+np[(i-k)|(1<<0)])(i必須包含0節(jié)點(diǎn),因?yàn)樽蛹赡懿缓?節(jié)點(diǎn),所以要和1<<0或起來,這樣才是將兩個(gè)裁判所走的邊權(quán)和合并)。
*/
void GetDist()
{for(int i=0;i<n;++i){for(int j=i+1;j<n;++j){mp[i][j]=mp[j][i]=ceil(sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));}}
}
int TSP_SECOND()
{GetDist();for(int i=1;i<(1<<n);++i)//求出各種路徑一種裁判的消費(fèi)if(isok[i]){for(int j=0;j<n;++j){if(i&(1<<j)){np[i]=min(np[i],cost[j][i]+mp[j][0]);for(int k=0;k<n;++k)if((i&(1<<k))==0)cost[k][i|(1<<k)]=min(cost[k][i|(1<<k)],cost[j][i]+mp[j][k]);}}}for(int i=1;i<(1<<n);++i)//多裁判消費(fèi)if(i&1)for(int j=(i-1)&i;j;j=(j-1)&i)np[i]=min(np[i],np[j|1]+np[(i-j)|1]);return np[(1<<n)-1];
}
?
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的【hdu4281状态压缩+01背包+多旅行商问题】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。