題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=3339php
大體題意是說:有n個電站,每一個電站都有必定的電量,電站之間有必定距離,咱們要從0點出發去佔領一些電站,使得佔領的電站電量之和超過總電量的一半,求達到條件所要走的最短距離。若是可能的話,輸出距離,不然輸出不可能。ios
思路:咱們從0點開始派出一些tank去佔領一些電站,坦克到每一個電站都有必定距離,而佔領每一個電站以後能夠獲得必定電量,距離就至關於體積v,電量就至關於價值w,這不是就01揹包嗎?01揹包一般的問法是給定體積,求得到最大的價值,這裏的問法是給訂價值,求剛好獲得或多於該價值時的最小體積。咱們只要從前向後搜索,找到第一個大於該價值的體積便可。ide
不過一開始我就被坑了,我令inf=0x7fffffff,而後就wa了好屢次,最後該成小一些的數,就過了,orz;spa
1 #include<iostream> 2 #include<cstring> 3 const int N=111; 4 const int inf=0x7fffff; 5 using namespace std; 6 int n,m; 7 int edge[N][N]; 8 int visited[N]; 9 int dist[N]; 10 int dp[N*N],power[N]; 11 12 void Dijkstra(int v0){ 13 memset(visited,0,sizeof(visited)); 14 for(int i=1;i<=n;i++){ 15 dist[i]=edge[v0][i]; 16 } 17 visited[v0]=1; 18 for(int i=1;i<n;i++){ 19 int min=inf,u=v0; 20 for(int j=1;j<=n;j++){ 21 if(!visited[j]&&dist[j]<min){ 22 min=dist[j],u=j; 23 } 24 } 25 if(min==inf)return ; 26 visited[u]=1; 27 for(int k=1;k<=n;k++){ 28 if(!visited[k]&&dist[u]+edge[u][k]<dist[k]){ 29 dist[k]=dist[u]+edge[u][k]; 30 } 31 } 32 } 33 } 34 35 int main(){ 36 int _case; 37 scanf("%d",&_case); 38 while(_case--){ 39 scanf("%d%d",&n,&m); 40 for(int i=0;i<=n;i++){ 41 for(int j=0;j<=n;j++){ 42 if(i==j){ 43 edge[i][j]=0; 44 }else 45 edge[i][j]=inf; 46 } 47 } 48 int x,y,d; 49 for(int i=1;i<=m;i++){ 50 scanf("%d%d%d",&x,&y,&d); 51 if(d<edge[x][y]){ 52 edge[x][y]=edge[y][x]=d; 53 } 54 } 55 for(int i=1;i<=n;i++){ 56 scanf("%d",&power[i]); 57 } 58 Dijkstra(0); 59 bool flag=true; 60 int v=0,w=0; 61 for(int i=1;i<=n;i++){ 62 w+=power[i]; 63 v+=dist[i]; 64 if(dist[i]==inf){ 65 flag=false; 66 break; 67 } 68 } 69 if(!flag){ 70 printf("impossible\n"); 71 continue; 72 } 73 for(int i=0;i<=v;i++){ 74 dp[i]=0; 75 } 76 for(int i=1;i<=n;i++){ 77 for(int j=v;j-dist[i]>=0;j--){ 78 dp[j]=(dp[j-dist[i]]+power[i])>dp[j]?(dp[j-dist[i]]+power[i]):dp[j]; 79 } 80 } 81 w=w/2+1; 82 for(int i=1;i<=v;i++){ 83 if(dp[i]>=w){ 84 printf("%d\n",i); 85 break; 86 } 87 } 88 } 89 return 0; 90 }