poj 3229 The Best Travel Design ( 图论+状态压缩 )

The Best Travel Design
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 1359   Accepted: 340

Description

Dou Nai is an excellent ACM programmer, and he felt so tired recently that he wants to release himself from the hard work. He plans a travel to Xin Jiang .With the influence of literature, he wishes to visit Tian Chi, Da Ban Town, Lou Lan mysterious town , Yi Li , and other sights that also have great attraction to him. But the summer vocation time is not long. He must come back before the end of the summer vocation. For visiting more sights and all the necessary sights, he should make a thorough plan. Unfortunately, he is too tired to move, so you must help him to make this plan. Here are some prerequisites: there are two ways of transportation, bus and train, and velocity of the bus is 120km/h and the train is 80km/h. Suppose the travel is started from Urumuqi (point 1), and the end of the travel route is Urumuqi too. You need to spend some time to visit the sights, but the time of each visit is not always equal. Suppose we spend 12 hours on traveling every day.

Input

There are several test cases. For each case, the first line is three integers N, M and K. N (1<=n<=15) is the number of sights, M(0<=M<=N) is total sights he must arrived (sight 1 is always must be arrived) and K is total traveling time (per day). The second line is M integers which sights he must visited. The third line is N integers, the i th integer means the time he will stay in the sight i (per hour). Then several lines follow. Each line is four integers x, y, len and kind, 1<=x, y<=n, 0<len<=1000, means there is a bidirectional path between sights x and y, the distance is len, kind=0 means x and y are connected by train, kind=1 is by bus.
x=y=len=kind=0 means end of the path explanation.
N=M=K=0 means end of the input.

Output

For each case, output maximum sights he will travel with all necessary sights visited or "No Solution" if he can't travel all the sights he like best in time.

Sample Input

3 3 3
1 2 3
10 8 6
1 2 120 0
1 3 60 1
2 3 50 1
0 0 0 0
3 3 2
1 2 3
10 8 6
1 2 120 0
1 3 60 1
2 3 50 1
0 0 0 0
0 0 0

Sample Output

3
No Solution

Source


题意:
很多旅游景点,在给定时间内,给定要游览的点。点与点之间由不同长度的路连接。有两种交通方式------火车和BUS,速度不同且已知。从起点1出发,要求在给定时间内
把给定景点游览完且回到起点1,并且游览的景点最多。输出最多的游览个数。如果给定景点在限定时间内不能都游览完则输出no solution.(大写)。每个景点的stay的时间
也已知。

注:给定游览时间以天计算,而且每天的游览时间为12个小时。


代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define INF 1e9
using namespace std;

double a[20],t;
double map[22][22];
double dp[20][1<<20];
int n,m;

void init()
{
    int i,j;
    for(i=0;i<n;i++)
    {
        map[i][i]=0;
        for(j=0;j<n;j++)
        {
            map[i][j]=INF;
        }
        for(j=0;j<(1<<n);j++)   //所有状态下i为终点的用时都初始化为无穷大
        {
            dp[i][j]=INF;
        }
    }
}
void floyd()
{
    int i,j,k;
    for(k=0; k<n; k++)         //k为i和j之间的点
    {
        for(i=0; i<n; i++)
        {
            if(i!=k&&map[i][k]<INF)
                for(j=0; j<n; j++)
                {
                    if(i!=j&&map[k][j]<INF)
                    {
                        map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
                    }
                }
        }
    }
}

int main()
{
    int res,cnt,tmp,ans,x,y,kind,len,i,j,k;
    while(scanf("%d%d%lf",&n,&m,&t),(n||m||t))
    {
        res=0,ans=-1;
        double day=t*12.0;
        init();
        for(i=1;i<=m;i++)
        {
            scanf("%d",&k);
            res+=1<<(k-1);     //res记录要访问的所有点的状态,便于之后对照。
        }
        for(i=0;i<n;i++)
            scanf("%lf",&a[i]);         //a[i]记录每个景点stay的用时
        while(scanf("%d%d%d%d",&x,&y,&len,&kind),(x||y||len||kind))
        {
            x--,y--;                   //转化为以0为起点
            double hour=len*1.0/(kind?120.0:80.0);
            map[x][y]=min(hour,map[x][y]);
            map[y][x]=min(hour,map[y][x]);
        }
        floyd();
        for(i=1;i<n;i++)
            dp[i][1<<i]=map[0][i]+a[i];    //初始化从起点直接到i的用时
        for(j=0;j<(1<<n);j++)           //枚举所有状态
        {
            for(i=0;i<n;i++)        //在起点0和i之间取点k来更新最短用时,dp实现
            {
                if((j&(1<<i))&&j!=(1<<i))        //j状态包含0-->i的状态且不等于那个状态
                {
                    for(k=0;k<n;k++)
                    {
                        if((j&(1<<k)&&i!=k&&j!=(1<<k)))
                           dp[i][j]=min(dp[i][j],dp[k][j-(1<<i)]+map[k][i]+a[i]);
                    }
                    if(((j&res)==res)&&map[i][0]+dp[i][j]<=day)   //如果j状态包含res记录的状态且用时小于等于限定的时间
                    {
                        tmp=j;
                        cnt=0;
                        while(tmp)       //j状态每一位的状态进行遍历
                        {
                            if(tmp%2) cnt++;   //为1的位则cnt++
                            tmp=tmp>>1;         
                        }
                        ans=max(cnt,ans);      //更新最大值
                        //printf("test: %d\n",ans);
                    }
                }
            }
        }
        if(ans>=0)
            printf("%d\n",ans);
        else printf("No Solution\n");
    }
    return 0;
}

//391MS


分析:
已经游览的每个点用1表示,未游览的用0表示。某时刻的游览状态就可以用一个整数的二进制形式表示。
dp[i][j]表示j状态下以i为终点的用时。
先用floyd处理每两点的最短时间。然后用floyd思想来进行动态规划。
dp方程: dp[i][j]=min(dp[i][j],dp[k][j-(1<<i)]+map[k][i]+a[i])
状态压缩的时候为了表示方便,把起点为1转化为起点为0。

如果以1为起点的话,确实不好处理。因为n个景点就有n种状态。每一位代表一个景点的状态。那么从1开始就只能用n位
表示n-1种状态。

转化为以编号0的点为起点只需每次把点的坐标前移一个即减1就行了。

注意:因为算速度的时候可能不能整除,故用double存与记录时间有关的变量为宜。并且相关的计算也要注意将整形转化
            为浮点型。


 

11989507

fukan

3229

Accepted

4148K

391MS

C++

2504B

2013-08-15 22:30:24


 

posted @ 2013-08-16 18:50  pangbangb  阅读(404)  评论(0编辑  收藏  举报