D - 和谐(最短路+01背包)

自1945年以来,当美国的曼哈顿项目小组引爆了第一颗核弹时,全球的核武器数量急剧增加。
 如今,FZU的一个名叫AekdyCoin的疯狂男孩拥有核武器,想要毁灭我们的世界。幸运的是,我们神秘的间谍网络已经得到了他的计划。现在,我们需要阻止它。
 但这项艰巨的任务显然并不容易。首先,我们知道,核武器的操作系统由一些连接的电站组成,它们构成了一个庞大而复杂的电网。每个电站都有它的功率值。要启动核武器,它必须消耗电网一半的电力。所以首先,我们需要将一半以上的能量分散。我们的坦克已经为我们在基地的行动做好了准备(ID是0),我们必须在路上驾驶它们。至于发电站,只有当我们的坦克停在那里时,我们才能控制它们。1单位距离花费1单位油。我们有足够的坦克使用。
 现在我们的指挥官想知道这次行动的最小石油成本。
Input
 输入数据的第一行包含一个整数T,表示文件中测试点的数量。
 对于每组数据,第一行有两个整数n(1<= n<= 100), m(1<= m<= 10000),指定站点的数量(id为1、2、3…n),以及站点之间的道路数量(双向)。
 接下来的m行,每一行都有三个整数 st(0<= st<= n), ed(0<= ed<= n), dis(0<= dis<= 100),指定起始点、结束点和它们之间的距离。
 接下来的n行,每一行都有一个整数pow(1<= pow<= 100),按ID顺序表示各电站的功率。
Output
 输出最低的石油成本。
 若不存在则输出 “impossible”(不带引号).
Sample Input
2
2 3
0 2 9
2 1 3
1 0 2
1
3
2 1
2 1 3
1
3
Sample Output
5
impossible

注意:是要选择1~n的点放坦克,而不是路过而已;
然后这里求最短路用的是Floyd,求出0到1~n各个点的最短路,然后01背包选点;

#include <iostream>
#include <stdio.h>
#include <string>
#include<cstring>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 200;
int mz[maxn][maxn],path[maxn][maxn],val[maxn];
int n,m;
void floyd()
{
    for(int k=0;k<=n;k++)
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                if(mz[i][j]>mz[i][k]+mz[k][j]){
                    mz[i][j]=mz[i][k]+mz[k][j];
                    path[i][j]=k;
                }
}
//忽略get_path函数以及path数组
void get_path(int u,int v,vector<pair<int,int>>&p)
{
    if(path[u][v]==-1)p.push_back({u,v});
    else{
        int mid=path[u][v];
        get_path(u,mid,p);
        get_path(mid,v,p);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--){
        memset(mz,INF,sizeof(mz));
        memset(path,-1,sizeof(path));
        memset(val,0,sizeof(val));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(a==b)continue;
            if(mz[a][b]!=INF){
                int s=mz[a][b];
                mz[a][b]=min(c,s);
                mz[b][a]=mz[a][b];
            } else{
                mz[a][b]=c;
                mz[b][a]=mz[a][b];
            }
        }
        int sum=0;
        for(int i=1;i<=n;i++) {
            scanf("%d", &val[i]);
            sum+=val[i];
        }
        sum/=2;
        floyd();
        int temp=0;
        for(int i=1;i<=n;i++)
            if(mz[0][i]!=INF)
                temp+=mz[0][i];
        int dp[10005];
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            for(int j=temp;j>=mz[0][i];j--)
            {
                dp[j]=max(dp[j],dp[j-mz[0][i]]+val[i]);
            }
        bool flag=0;
        for(int i=0;i<=temp;i++)
            if(dp[i]>sum){
                printf("%d\n",i);
                flag=1;
                break;
            }
        if(!flag)
            printf("impossible\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值