hdu 3339 最短路+背包

/*
题意:给出一个0~n组成的图,1~n的点上分布着值为pow的电站,给出图的m条边以及
距离,从0出发到n个点中的x个点的行走距离和最小,且x个点的pow之和必须超过总的pow
和的一半;

题解:最短路+01背包
先求出0到所有点的最短距离,然后通过以行走的距离为背包,pow的和为价值,设将所有
点遍历走的距离值为sum,即要求0~sum的dp值,即当距离为v时,dp[v]为pow的最大的和,
因此dp完之后从0~sum遍历找出最小的v满足pow的和大于总和一半即可。

注意:重边、不连通的点、是多于一半的power,等于不行
*/
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

#define Max 1000000001

using namespace std;

struct nod
{
    int power;
    int oil;
}s[105];

int p;
int dp[60050],dist[105];
int map[105][105];
bool vis[105];

void dijkstra(int next, int n)//迪杰斯特拉算法求最短路,next为起点
{
    for(int i=0; i<=n; i++)
        dist[i] = Max;
    memset(vis,false,sizeof(vis));
    dist[next] = 0;
    for(int i=0; i<=n; i++)
    {
        int mindis = Max;
        for(int j=0; j<=n; j++)
        {
            if (!vis[j] && dist[j] < mindis)//找出未访问的点中路径最短的点并赋给node
            {
                mindis = dist[j];
                next = j;
            }
        }
        if (mindis == Max)//当点已经遍历完,break;
            break;
        vis[next] = true;
        for(int j=0; j<=n; j++)
            if (!vis[j] && map[next][j] > 0 && dist[next]+map[next][j] < dist[j])
                //以next为基点对其它未访问的点进行松弛
                dist[j] = dist[next]+map[next][j];
    }
}

bool cmp(nod a, nod b)
{
    return a.oil < b.oil;
}

int main(void)
{
    int n,q,fr,to,price,allpower;
    cin >> n;
    while (n--)
    {
        cin >> p >> q;
        allpower = 0;
        for(int i=0; i<=p; i++)
            for(int j=0; j<=p; j++)
            {
                map[i][j] = Max;  
            } 
        while (q--)
        {
            cin >> fr >> to >> price;
            if (map[fr][to] > price)
                map[fr][to] = map[to][fr] = price;
        }
        for(int i=1; i<=p; i++)
        {
            cin >> s[i].power;
            allpower += s[i].power;
        }
        dijkstra(0,p);
        int alloil, num;
        alloil = 0;
        num = 0;
        for(int i=1; i<=p; i++)
        {
            if (dist[i] < Max)
            {
                alloil += dist[i];
                num++;
            }
            s[i].oil = dist[i];
        }
        sort(s+1,s+p+1,cmp);
        int ans = 0;
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=num; i++)
            for(int v = alloil; v >= s[i].oil; v--)
                dp[v] = max(dp[v],dp[v-s[i].oil] + s[i].power);
        int i;
        for(i=0; i<=alloil; i++)
            if (dp[i] >= allpower/2+1)
                break;
        if (i <= alloil)
            cout << i << endl;
        else
            cout << "impossible" << endl;
    }
    return 0;
}

 

posted @ 2014-03-21 00:03  辛力啤  阅读(391)  评论(0编辑  收藏  举报