HDU 3339 In Action 最短路+01背包

来源:互联网 发布:易观智库外卖数据 编辑:程序博客网 时间:2024/05/01 06:28

题意:有一个基地0,坦克从里面出来,给n个点,标号1~n,每个点有一个权值,表示此点拥有的电量,有m条边,每条边有一个权值表示坦克走此边所要的耗费的油量。现在要用坦克占领点,只有一个坦克到那里,才算占领,一个坦克只能占领一个点,占领之后就不能动了,有无线多的坦克可以调用,现在问,如何花费最小的总油量使得坦克占领的电量总和达到所有电量的一半多?


解法:可以通过spfa得到从0点出发的单源最短路,现在把所有的油量,当成是一个背包的总容量,每一个点的油量当成是价值,每一个点的容量为dis[0-k](0点到这个点的最短路),通过01背包可以得到dp[k]:使用k的容量,可以得到的最大电量。


#include<iostream>#include<cstring>#include<cstdio>#include<queue>#define inf 0x7fffffffusing namespace std;const int nodes=100+5;const int edges=20000+50;int n,m,dp[10000+500],power[100+5],dis[nodes];struct node{int v,next,w;}e[edges];int head[nodes],cnt;void Init(){memset(head,-1,sizeof(head));cnt=0;}void add(int a,int b,int c){e[cnt].v=b;e[cnt].w=c;e[cnt].next=head[a];head[a]=cnt++;}void spfa(){int vis[nodes];queue<int>q;while(!q.empty()) q.pop();for(int i=0;i<=n;i++){dis[i]=inf;vis[i]=0;}vis[0]=1;dis[0]=0;q.push(0);while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(int i=head[u];i+1;i=e[i].next){int v=e[i].v;if(dis[v]>dis[u]+e[i].w){dis[v]=dis[u]+e[i].w;if(!vis[v]){vis[v]=1;q.push(v);}}}}}int Max(int a,int b){if(a>b) return a;return b; }int main(){int test;scanf("%d",&test);while(test--){int sum=0,oil=0;Init();scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b,a,c);}for(int i=1;i<=n;i++){scanf("%d",&power[i]);sum+=power[i];}spfa();sum/=2;for(int i=1;i<=n;i++){if(dis[i]!=inf)oil+=dis[i];}memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++){for(int j=oil;j>=dis[i];j--){dp[j]=Max(dp[j],dp[j-dis[i]]+power[i]);}}int mark=0;for(int i=0;i<=oil;i++){if(dp[i]>sum){mark=i;break;}}if(mark) printf("%d\n",mark);else printf("impossible\n");}return 0;} 

0 0
原创粉丝点击