HDU3339 In Action 【最短路】+【01背包】

<题目链接>

题目大意:

给出一个0~n组成的图,1~n的点上分布着值为pow的电站,给出图的m条边以及距离,从0出发到n个点中的x个点的行走距离和最小(因为是每炸一个点派出一辆坦克),且x个点的pow之和必须超过总的pow和的一半。

解题分析:

由于本题数据范围很小,只有100,所以我们能够用floyed算出0到任意一点的最短距离,然后将所有0可达的点看成物品,0到它们的最短距离看成体积,这样将所有可达物品最短距离之和看成背包容量,这些可达点的pow看成价值,然后再用01背包。dp[i]表示在总共走i距离的情况下,所能获得的最大价值。所以,在用01背包计算dp[1~sumvol]的所有值后,我们就可以遍历总共走过的距离i,当dp[i]恰好大于总价值一半的时候,此时的i就是总共的最短距离。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long 
const int INF=0x3f3f3f3f;
int n,m;
int mpa[110][110];
int val[110],vol[110];
const int maxn=1000000+1000;     
int dp[maxn];

void floyed(){      //floyed计算0到各点的最短路
    for(int i=0;i<=n;i++){
        for(int j=0;j<=n;j++){
            for(int k=0;k<=n;k++){
                if(mpa[j][k]>mpa[j][i]+mpa[i][k]){
                    mpa[j][k]=mpa[j][i]+mpa[i][k];
                }
            }
        }
    }
}

int main(){
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&m);

        for(int i=0;i<=n;i++){      //mpa[][]数组初始化
            for(int j=0;j<=n;j++){
                if(i==j)mpa[i][j]=0;
                else mpa[i][j]=INF;
            }
        }

        for(int i=1;i<=m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(c<mpa[a][b]){       //去重边
                mpa[a][b]=mpa[b][a]=c;
            }
        }
        int sumval=0;     //所有点的总价值
        for(int i=1;i<=n;i++){
            scanf("%d",&val[i]);
            sumval+=val[i];
        }

        floyed();
        int sumvol=0;      //0到所有可达点的最短距离之和,作为01背包的容量
        for(int i=1;i<=n;i++){
            if(mpa[0][i]!=INF)sumvol+=mpa[0][i];       
            vol[i]=mpa[0][i];     //把这段距离看成物品的体积
        }

        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            for(int j=sumvol;j>=vol[i];j--){
                dp[j]=max(dp[j],dp[j-vol[i]]+val[i]);    //dp[j]表示在总距离为j的情况下所能得到的最大价值
            }
        }
        int ans=-INF;
        for(int i=1;i<=sumvol;i++){      
            if(dp[i]>(sumval/2)){    //当dp[i]的值大于sum/2时,此时的i就是符合条件的最短距离
                ans=i;
                break;
            }
        }
        if(ans==-INF)printf("impossible\n");
        else printf("%d\n",ans);
    }
    return 0;
}

 

 

2018-09-04

posted @ 2018-09-04 09:22  悠悠呦~  阅读(301)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end