Hdu 4284 Travel(状态压缩)

Travel

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3161    Accepted Submission(s): 842


Problem Description
  PP loves travel. Her dream is to travel around country A which consists of N cities and M roads connecting them. PP has measured the money each road costs. But she still has one more problem: she doesn't have enough money. So she must work during her travel. She has chosen some cities that she must visit and stay to work. In City_i she can do some work to earn Ci money, but before that she has to pay Di money to get the work license. She can't work in that city if she doesn't get the license but she can go through the city without license. In each chosen city, PP can only earn money and get license once. In other cities, she will not earn or pay money so that you can consider Ci=Di=0. Please help her make a plan to visit all chosen cities and get license in all of them under all rules above.
  PP lives in city 1, and she will start her journey from city 1. and end her journey at city 1 too.
 

Input
  The first line of input consists of one integer T which means T cases will follow.
  Then follows T cases, each of which begins with three integers: the number of cities N (N <= 100) , number of roads M (M <= 5000) and her initiative money Money (Money <= 10^5) .
  Then follows M lines. Each contains three integers u, v, w, which means there is a road between city u and city v and the cost is w. u and v are between 1 and N (inclusive), w <= 10^5.
  Then follows a integer H (H <= 15) , which is the number of chosen cities.
  Then follows H lines. Each contains three integers Num, Ci, Di, which means the i_th chosen city number and Ci, Di described above.(Ci, Di <= 10^5)
 

Output
  If PP can visit all chosen cities and get all licenses, output "YES", otherwise output "NO".
 

Sample Input
2 4 5 10 1 2 1 2 3 2 1 3 2 1 4 1 3 4 2 3 1 8 5 2 5 2 3 10 1 2 1 100 1 2 10000 1 2 100000 1
 

Sample Output
YES NO
 


题意:
给出一些城市,从1出发,旅游一圈回到1。因为花费可能不够,所以选择一些城市打工,打工之前须要花费d买一个证,工资为c。选中的城市必须去工作一次。并且仅仅能工作一次。问能不能完毕旅行
题解:
先floyed出两个城市间最小的费用,用dp[i][j]保存当前i状态下到达j城市的最小费用。


AC  CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<map>

#define N 110
#define Mod 10000007
#define lson l,mid,idx<<1
#define rson mid+1,r,idx<<1|1
#define lc idx<<1
#define rc idx<<1|1
const double EPS = 1e-11;
const double PI = acos ( -1.0 );
const double E = 2.718281828;
typedef long long ll;

const int INF = 1000010;

using namespace std;

int  n, m, money, num;
int mp[N][N];///记录两个城市间的最小费用
int dp[ ( 1 << 15 ) + 1][17];///以i状态到达j城市的最小花费

struct jobs
{
    int city;
    int c, d;
} H[17];

void floyed() ///两城市之间最小费用
{
    for ( int k = 1; k <= n; k++ )
        for ( int i = 1; i <= n; i++ )
            for ( int  j = 1; j <= n; j++ )
            {
                if ( mp[i][j] > mp[i][k] + mp[k][j] )
                    mp[i][j] = mp[i][k] + mp[k][j];
            }
}

int DP()
{
    for ( int i = 0; i < ( 1 << num ); i++ )
    {
        for ( int j = 0; j < num; j++ )
        {
            if ( dp[i][j] == INF )
                continue;
            for ( int k = 0; k < num; k++ )
            {
                if ( ( ( 1 << k ) &i ) || ( k == j ) ) ///第k座城市已选
                    continue;
                if ( money - dp[i][j] - mp[H[j].city][H[k].city] < H[k].d ) ///剩下的钱不够买license
                    continue;
                dp[i | ( 1 << k )][k] = min ( dp[i | ( 1 << k )][k], dp[i][j] + mp[H[j].city][H[k].city] + H[k].d - H[k].c );
            }
        }
    }
    int x = ( 1 << num ) - 1;
    for ( int i = 0; i < num; i++ )
        if ( dp[x][i] + mp[H[i].city][1] <= money ) ///最后一座城市回到第一座城市
            return 1;
    return 0;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    cin >> t;
    while ( t-- )
    {
        scanf ( "%d %d %d", &n, &m, &money );
        int x, y, z;
        for ( int i = 0; i <= n; i++ )
            for ( int j = 0; j <= i; j++ )
            {
                if ( j == i )
                    mp[i][j] = 0;
                else
                    mp[i][j] = mp[j][i] = INF;
            }
        for ( int i = 0; i < m; i++ )
        {
            scanf ( "%d%d%d", &x, &y, &z );
            if ( mp[x][y] > z )
                mp[x][y] = mp[y][x] = z;
        }
        floyed();
        scanf ( "%d", &num );
        for ( int i = 0; i < ( 1 << num ); i++ )
            for ( int j = 0; j < num; j++ )
                dp[i][j] = INF;
        for ( int i = 0; i < num; i++ )
        {
            scanf ( "%d %d %d", &H[i].city, &H[i].c, &H[i].d );
            if ( money >= mp[1][H[i].city] + H[i].d )
                dp[1 << i][i] = mp[1][H[i].city] - H[i].c + H[i].d;
        }
        if ( DP() )
            cout << "YES\n";
        else cout << "NO\n";
    }
    return 0;
}


posted @ 2017-08-07 08:39  jzdwajue  阅读(239)  评论(0编辑  收藏  举报