hdu 4284 Travel

http://acm.hdu.edu.cn/showproblem.php?pid=4284

这题后台数据相当强呀 

思路:先用flody  求得任意两点间的最短距离

然后再用 状态压缩+DP

dist [ i ] [ j ]  表示已经到 i 状态压缩表示的城市 拿到证件 打工 而且现在在 第 j 个要去的城市  这种情况下剩余的最多钱

不断更新  最后看是否有满足条件 去过所以要去的城市 而且还能回到原点的  状态

代码及其注释:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <queue>

#include <algorithm>



#define LL long long



using namespace std;



const int N=103;

const int H=16;

const int INF=0x0fffffff;

int dist[1<<16][H];//此状态剩余最多钱

int d[N][N];//最短路

struct node

{

    int k,c,d;

}mem[H];//要去的城市相关信息

bool cmp(node x,node y)//按城市序号排序 主要是让原点 在 0 位置

{

    return x.k<y.k;

}

int main()

{

    //freopen("data.txt","r",stdin);

    int T;

    scanf("%d",&T);

    while(T--)

    {

        int n,m,money,h,K;;

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

        for(int i=1;i<=n;++i)

        for(int j=1;j<=n;++j)

        {

            if(i==j)d[i][j]=0;

            else d[i][j]=INF;//初始化

        }

        while(m--)

        {

            int i,j,p;

            scanf("%d %d %d",&i,&j,&p);

            d[i][j]=d[j][i]=min(d[i][j],p);

        }

        scanf("%d",&h);

        int have1=false;

        for(int i=0;i<h;++i)

        {

            scanf("%d %d %d",&mem[i].k,&mem[i].c,&mem[i].d);

            if(mem[i].k==1)

            have1=true;

        }

        if(!have1)//如果原点不在则将原点加入  这样不会影响最终结果 而且便于运算

        {

            mem[h].c=mem[h].d=0;

            mem[h].k=1;++h;

        }

        sort(mem,mem+h,cmp);

        for(int l=1;l<=n;++l)

        for(int i=1;i<=n;++i)

        for(int j=1;j<=n;++j)

        if(d[i][j]>d[i][l]+d[l][j])

        d[i][j]=d[i][l]+d[l][j];//求最短路

        memset(dist,-1,sizeof(dist));

        K=(1<<h)-1;

        dist[0][0]=money;//在没有去过任何城市时 在第0个要去的城市(原点)时所有钱

        for(int i=0;i<K;++i)

        {

            for(int j=0;j<h;++j)//i 和 j表示的顺序不能变 因为更新时是想i 变大的方向更新

            {

                if(dist[i][j]==-1)

                continue;

                for(int l=0;l<h;++l)

                {

                    int temp=i|(1<<l);

                    if(temp==i)//已经去过 拿证件 打工

                    continue;

                    int more=dist[i][j]-d[mem[j].k][mem[l].k]-mem[l].d;//看是否可以成功到达 并且拿到证件

                    if(more<0)

                    continue ;

                    dist[temp][l]=max(dist[temp][l],more+mem[l].c);//更新

                }

            }

        }

        bool ans=false;

        for(int i=0;i<h;++i)

        if(dist[K][i]>=d[mem[i].k][mem[0].k])//去过所有要去的城市 而且能回到原点

        {ans=true;break;}

        if(ans)

        printf("YES\n");

        else

        printf("NO\n");

    }

    return 0;

}

 

你可能感兴趣的:(HDU)