您的位置:首页 > 其它

hdu 3339(01背包+最短路)

2013-03-07 15:30 246 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3339

大致题意是说:有n个电站,每个电站都有一定的电量,电站之间有一定距离,我们要从0点出发去占领一些电站,使得占领的电站电量之和超过总电量的一半,求达到条件所要走的最短距离。如果可能的话,输出距离,否则输出不可能。

思路:我们从0点开始派出一些tank去占领一些电站,坦克到每个电站都有一定距离,而占领每个电站之后可以得到一定电量,距离就相当于体积v,电量就相当于价值w,这不是就01背包吗?01背包通常的问法是给定体积,求获得最大的价值,这里的问法是给定价值,求恰好得到或多于该价值时的最小体积。我们只要从前向后搜索,找到第一个大于该价值的体积即可。

不过一开始我就被坑了,我令inf=0x7fffffff,然后就wa了好多次,最后该成小一些的数,就过了,orz;

View Code

#include<iostream>
#include<cstring>
const int N=111;
const int inf=0x7fffff;
using namespace std;
int n,m;
int edge

;
int visited
;
int dist
;
int dp[N*N],power
;

void Dijkstra(int v0){
memset(visited,0,sizeof(visited));
for(int i=1;i<=n;i++){
dist[i]=edge[v0][i];
}
visited[v0]=1;
for(int i=1;i<n;i++){
int min=inf,u=v0;
for(int j=1;j<=n;j++){
if(!visited[j]&&dist[j]<min){
min=dist[j],u=j;
}
}
if(min==inf)return ;
visited[u]=1;
for(int k=1;k<=n;k++){
if(!visited[k]&&dist[u]+edge[u][k]<dist[k]){
dist[k]=dist[u]+edge[u][k];
}
}
}
}

int main(){
int _case;
scanf("%d",&_case);
while(_case--){
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
if(i==j){
edge[i][j]=0;
}else
edge[i][j]=inf;
}
}
int x,y,d;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&d);
if(d<edge[x][y]){
edge[x][y]=edge[y][x]=d;
}
}
for(int i=1;i<=n;i++){
scanf("%d",&power[i]);
}
Dijkstra(0);
bool flag=true;
int v=0,w=0;
for(int i=1;i<=n;i++){
w+=power[i];
v+=dist[i];
if(dist[i]==inf){
flag=false;
break;
}
}
if(!flag){
printf("impossible\n");
continue;
}
for(int i=0;i<=v;i++){
dp[i]=0;
}
for(int i=1;i<=n;i++){
for(int j=v;j-dist[i]>=0;j--){
dp[j]=(dp[j-dist[i]]+power[i])>dp[j]?(dp[j-dist[i]]+power[i]):dp[j];
}
}
w=w/2+1;
for(int i=1;i<=v;i++){
if(dp[i]>=w){
printf("%d\n",i);
break;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: