hdu 3339 In Action (最短路+01背包)
大致题意是说:有n个电站,每个电站都有一定的电量,电站之间有一定距离,我们要从0点出发去占领一些电站,使得占领的电站电量之和超过总电量的一半,求达到条件所要走的最短距离。如果可能的话,输出距离,否则输出不可能。我们知道电站都是连通的,只要0点与任何一个电站连通,我们就可以占领所有电站,如果0点不与任何一个电站相连,就是不可能实现,也就是说0点到任何一个电站的距离都是无穷。
我们从0点开始派出一些坦克去占领一些电站,坦克到每个电站都有一定距离,而占领每个电站之后可以得到一定电量,距离就相当于体积,电量就相当于价值,这不是就01背包吗?01背包通常的问法是给定体积,求获得最大的价值,这里的问法是给定价值,求恰好得到或多于该价值时的最小体积。我们只要从前向后搜索,找到第一个大于该价值的体积即可。
PS:一开始无限的wa,主要有俩个原因,一个是题意理解错了,忽略了选中的电站要留一辆tank在那里,所以,我直接将最短的路径保存之后,遍历所有路径求出最小的消耗
,还有一个就是数组开小了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream>
#include<algorithm>
#define MAXN (100+10)
#define INF 10000000
using namespace std;
int g[MAXN][MAXN],n;
int dist[MAXN],p[MAXN],dp[MAXN*MAXN];
bool vis[MAXN];
void dijkstra()
{
int i,j,temp,min;
for(i=1;i<=n;i++)
{
vis[i]=false;
dist[i]=g[0][i];
}
for(i=1;i<n;i++)
{
min=INF;
for(j=1;j<=n;j++)
if(!vis[j] && dist[j]<min)
{
temp=j;
min=dist[j];
}
if(min==INF)
break;
vis[temp]=true;
for(j=1;j<=n;j++)
if(!vis[j] && dist[j]>dist[temp]+g[temp][j])
dist[j]=dist[temp]+g[temp][j];
}
}
int main()
{
int T,m,a,b,c;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
{
if(i==j) g[i][j]=0;
else
g[i][j]=INF;
}
while(m--)
{
scanf("%d %d %d",&a,&b,&c);
if(c<g[a][b])
g[a][b]=g[b][a]=c;
}
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
int w=0,sum=0;
dijkstra();
bool flag=true;
for(int i=1;i<=n;i++)
{
w+=p[i];
sum+=dist[i];
if(dist[i]==INF)
{
flag=false;
break;
}
}
if(!flag)
{
printf("impossible\n");
continue;
}
for(int i=0;i<=sum;i++)
dp[i]=0;
for(int i=1;i<=n;i++)
for(int j=sum;j>=dist[i];j--)
dp[j]=max(dp[j],dp[j-dist[i]]+p[i]);
w=w/2+1;
for(int i=1;i<=sum;i++)
if(dp[i]>=w)
{
printf("%d\n",i);
break;
}
}
return 0;
}