• 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
    ");
            else printf("%d
    ",ans);
        }
        return 0;
    }

    2018-09-04

  • 相关阅读:
    windows10装机小记
    Linus Benedict Torvalds hate FUD
    营销文章good
    商城趣聊4
    商城趣聊3
    商城趣聊2
    商城趣聊1
    temp
    学习代码检视方法 (摘自某图片)
    xilinx sdk闪退问题
  • 原文地址:https://www.cnblogs.com/00isok/p/9582505.html
Copyright © 2020-2023  润新知