In Action 最短路 + 01背包

1945年,美国的曼哈顿项目引爆了世界上第一颗核弹,从此,全球核武器的数量急剧增加。
 如今,CAPCOM®的一位名叫tgy的设计师竟拥有了核武器,想要毁灭世界(?)。然而,我们的舅舅已经提前得知了它的邪恶计划,必须阻止它!
 首先,tgy的核武器系统由一些电站组成,每个电站都提供一定的功率值,构成了一个庞大的供电网。想要启动核武器,必须消耗整个供电网一半的电力。所以,我们需要将总计提供一半以上功率的电站关闭,使得电网中的剩余功率低于最初的一半,阻止tgy发射核弹。我们的坦克已经在基地(id为0)做好了准备,对于每个供电站,只有当我们的坦克一直停在那里,我们才能控制它们。假设我们有足够多的坦克,每辆坦克行驶1单位距离花费1单位油。
 现在我们的指挥官想知道这次行动的最少油耗。

Input

 输入数据的第一行包含一个整数T,表示文件中测试点的数量。
 对于每组数据,第一行有两个整数n(1<= n<= 100), m(1<= m<= 10000),指定电站的数量(id为1、2、3…n,基地的id为0),以及站点之间的道路数量(双向)。
 接下来的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

思路

用Dijsktra算法或Floyd算法等最短路算法求出 0(基地)到 n(电站)的最短距离,再用01背包

01背包

二维

 for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= m; j++)
        {
            //  当前背包容量装不进第i个物品,则价值等于前i-1个物品
            if(j < v[i]) 
                f[i][j] = f[i - 1][j];
            // 能装,需进行决策是否选择第i个物品
            else    
                f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
        }           

一维

for(int i = 1; i <= n; i++)
{
    for(int j = m; j >= v[i]; j--)  
        f[j] = max(f[j], f[j - v[i]] + w[i]);
} 

AC代码

//Floyd
#include <iostream>
#include <cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 110, M = 10010;
int g[N][N];
int dp[M * 2], p[N];
bool st[N];
int n, m, k, dm, v;
int main()
{
    scanf("%d", &k);
    while (k--)
    {
        scanf("%d%d", &n, &dm);
        memset(dp, 0, sizeof dp);
        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;
        
        for (int i = 0; i < dm; i++)
        {
            int a, b, w;
            scanf("%d%d%d", &a, &b, &w);
            g[a][b] = g[b][a] = min(g[a][b], w);
        }
        for (int k = 0; k <= n; k++)
            for (int i = 0; i <= n; i++)
                for (int j = 0; j <= n; j++)
                    g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
        m = 0, v = 0;
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &p[i]);
            v += p[i];
            if (g[0][i] != INF)
            {
                m += g[0][i];
            }
        }
        for (int i = 1; i <= n; i++)
        {

            for (int j = m; j >= g[0][i]; j--)
            {
                dp[j] = max(dp[j], dp[j - g[0][i]] + p[i]);
            }
        }
        bool flat = false;
        int answer;
        for (int i = 0; i < m; i++)
        {
            if (dp[i] > v / 2)
            {
                answer = i;
                flat = true;
                break;
            }
        }
        if (flat)
        {
            printf("%d\n", answer);
        }
        else
        {
            puts("impossible");
        }
    }

    return 0;
}

 

//bellman_ford
#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 110, M = 10010;
int n, m, k, v, dm;
int dist[N], dp[M], p[N];
struct Edge
{
    int a, b, w;
} edges[M * 2];

void bellman_ford()
{
    memset(dist, INF, sizeof dist);
    dist[0] = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < 2 * m; j++)
        {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            if (dist[b] > dist[a] + w)
                dist[b] = dist[a] + w;
        }
    }
}
int main()
{
    scanf("%d", &k);
    while (k--)
    {
        scanf("%d%d", &n, &m);
        memset(dp, 0, sizeof dp);
        for (int i = 0; i < m; i++)
        {
            int a, b, w;
            scanf("%d%d%d", &a, &b, &w);
            edges[2 * i] = {a, b, w};
            edges[2 * i + 1] = {b, a, w};
        }
        v = 0, dm = 0;
        bellman_ford();
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &p[i]);
            v += p[i];
            if (dist[i] != INF)
            {
                dm += dist[i];
            }
        }
        for (int i = 1; i <= n; i++)
        {

            for (int j = dm; j >= dist[i]; j--)
            {
                dp[j] = max(dp[j], dp[j - dist[i]] + p[i]);
            }
        }
        bool flat = false;
        int answer;
        for (int i = 0; i < dm; i++)
        {
            if (dp[i] > v / 2)
            {
                answer = i;
                flat = true;
                break;
            }
        }
        if (flat)
        {
            printf("%d\n", answer);
        }
        else
        {
            puts("impossible");
        }
    }

    return 0;
}

最短路:鉴于y总

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值