天天看點

HDU-3339-In Action

ACM模版

描述

HDU-3339-In Action
HDU-3339-In Action

題解

最短路+背包。第一次做将這兩種算法組合的題,好題。

要求最少油耗使得系統癱瘓,而癱瘓的要求是控制的能量超過一半,那麼前者很容易想到需要先求最短路,但是求過最短路後并不是每一個電廠都要占領,要保證占領的電廠的總能量超過一半并且耗油最少,這就是01背包的問題了~~~

代碼

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

/*
 *  單源最短路徑,Dijkstra算法,鄰接矩陣形式,複雜度為O(n^2)
 *  求出源beg到所有點的最短路徑,傳入圖的頂點數和鄰接矩陣cost[][]
 *  傳回各點的最短路徑lowcost[],路徑pre[],pre[i]記錄beg到i路徑上的父節點,pre[beg] = -1
 *  可更改路徑權類型,但是權值必須為非負,下标0~n-1
 */
const int MAXN = ;
const int INF = ; //  表示無窮
bool vis[MAXN];
int pre[MAXN];

void Dijkstra(int cost[][MAXN], int lowcost[], int n, int beg)
{
    for (int i = ; i < n; i++)
    {
        lowcost[i] = INF;
        vis[i] = false;
        pre[i] = -;
    }
    lowcost[beg] = ;
    for (int j = ; j < n; j++)
    {
        int k = -;
        int min = INF;
        for (int i = ; i < n; i++)
        {
            if (!vis[i] && lowcost[i] < min)
            {
                min = lowcost[i];
                k = i;
            }
        }
        if (k == -)
        {
            break;
        }
        vis[k] = true;
        for (int i = ; i < n; i++)
        {
            if (!vis[i] && lowcost[k] + cost[k][i] < lowcost[i])
            {
                lowcost[i] = lowcost[k] + cost[k][i];
                pre[i] = k;
            }
        }
    }
}

int cost[MAXN][MAXN];
int lowcost[MAXN];
int power[MAXN];
int dp[MAXN * MAXN];

int main()
{
    int T;
    scanf("%d", &T);

    int n, m;
    while (T--)
    {
        memset(cost, , sizeof(cost));

        scanf("%d%d", &n, &m);

        int st, ed, val;
        while (m--)
        {
            scanf("%d%d%d", &st, &ed, &val);
            if (val < cost[st][ed])
            {
                cost[st][ed] = cost[ed][st] = val;
            }
        }

        int sum = ;
        for (int i = ; i <= n; i++)
        {
            scanf("%d", &power[i]);
            sum += power[i];
        }

        Dijkstra(cost, lowcost, n + , );

        memset(dp, , sizeof(dp));
        dp[] = ;

        for (int i = ; i <= n; i++)
        {
            for (int j = sum; j >= power[i]; j--)
            {
                dp[j] = min(dp[j], dp[j - power[i]] + lowcost[i]);
            }
        }

        int mid = sum /  + ;  //  大于一半
        int res = INF;
        for (int i = mid; i <= sum; i++)
        {
            if (dp[i] < res)
            {
                res = dp[i];
            }
        }

        if (res == INF)
        {
            printf("impossible\n");
        }
        else
        {
            printf("%d\n", res);
        }
    }

    return ;
}
           

參考

《最短路》