hdu 3339 In Action最短spfa+リュックサック


タイトルリンク
題意:n個の点と各点の電力値を与え、m本の道を与える.いくつかの点を選択し、その電力値の和が総電力値の半分より大きいことを保証した場合に最短経路和を求める.
まず初期点から各点への最短経路を求め,その後リュックサックの考え方でいくつかの点を選択し,距離と最小化した.各戦車は1点しか届かないことに注意してください.
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#define N 110
#define M 11000
#define INF 0x7ffffff
using namespace std;

int d[N],v[N],dp[M],n,mp[N][N],p[N];

void spfa()
{
    for(int i=0;i<=n;i++)   d[i]=INF,v[i]=0;
    queue<int> q;
    q.push(0);
    v[0]=1;
    d[0]=0;
    while(!q.empty())
    {
        int c=q.front();
        q.pop();
        v[c]=0;
        for(int i=0;i<=n;i++)
        {
            if(d[i]>d[c]+mp[c][i])
            {
                d[i]=d[c]+mp[c][i];
                if(!v[i])   v[i]=1,q.push(i);
            }
        }
    }
    return ;
}

int main()
{
    int T,m;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                mp[i][j]=INF;
        for(int i=0;i<m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if(mp[u][v]>w)  mp[u][v]=mp[v][u]=w;
        }
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i]);
            sum+=p[i];
        }
        spfa();
        for(int i=1;i<=sum;i++) dp[i]=INF;
        dp[0]=0;
        for(int i=1;i<=n;i++)
            for(int j=sum;j>=p[i];j--)
                dp[j]=min(dp[j],dp[j-p[i]]+d[i]);
        int ans=INF;
        for(int i=sum/2+1;i<=sum;i++) ans=min(ans,dp[i]);
        if(ans>=INF)    cout<<"impossible"<<endl;
        else    cout<<ans<<endl;
    }
}