Light oj 1316 - A Wedding Party(状压dp)

1316 - A Wedding Party
Time Limit: 3 second(s)Memory Limit: 32 MB

We all know that we have a big and exciting wedding party ahead. So we made a plan to go to buy a gift for the wedding party. We all gathered at a place and we were just about to buy the gift. Unfortunately, we find that we have a 'Team Practice Contest' ahead. Now before going to the contest we have to buy the gift. As time is too short we will try to buy the gift on the way to the contest. We will try to visit as many shops as possible. The city map is represented by a graph with N nodes and M edges. N nodes represent the N junctions and M edges represent the M unidirectional roads connecting the cities. Every road has a cost which represents the required time to use the road. The contest is running at junction N-1 and we will start our journey at junction 0. And there are exactly Sshops located at different junctions.

Now given the location of the shops you have to find the route from junction 0 to junction N-1 which will visit maximum number of shops with minimum time (first maximize the number of shops then minimize the time to visit them). We can visit a junction more than once.

Input

Input starts with an integer T (≤ 50), denoting the number of test cases.

Each case begins with three non negative integers N (2 ≤ N ≤ 500)M (1 ≤ M ≤ 10000) S (0 ≤ S ≤ 15). Next line contains S integers denoting the shop locations. Each of the next M lines contains three integers uv, w (0 < u, v < N, u ≠ v, 1 ≤ w ≤ 100) denoting a road from u to with cost w.

Output

For each case of input you have to print the case number and two integers representing maximum number of shops we can visit in the way and the minimum time required to reach junction N-1 after visiting maximum number of shops. If we cannot attend the contest, print "Impossible". See samples for more details.

Sample Input

Output for Sample Input

2

4 4 4

0 1 2 3

0 1 10

1 3 30

0 2 30

2 3 5

4 4 4

0 1 2 3

0 1 10

3 1 30

0 2 30

3 2 5

Case 1: 3 35

Case 2: Impossible

 


PROBLEM SETTER: MUHAMMAD RIFAYAT SAMEE
SPECIAL THANKS: JANE ALAM JAN

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>

#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)

#define bug printf("hihi\n")

#define eps 1e-12

typedef long long ll;

using namespace std;
#define INF 0x3f3f3f3f
#define N 505

int a[N][N];
int dis[N][N];
int dp[1<<18][18];
int n,m,k;
vector<int>g;
int d[N];
int vis[N];
int ca=0;
bool inin;
bool ininin;
int ans[N];

void dij(int s)
{
   int i,j;
   memset(d,INF,sizeof(d));
   d[s]=0;
   memset(vis,0,sizeof(vis));
   for(i=0;i<n;i++)
   {
       int now,temp=INF;
       for(j=0;j<n;j++)
         if(d[j]<temp&&!vis[j])
       {
           now=j;
           temp=d[j];
       }
       if(temp>=INF) return ;
       vis[now]=1;
       for(int j=0;j<n;j++)
          if(!vis[j]&&a[now][j]<INF)
             d[j]=min(d[j],d[now]+a[now][j]);
   }
}

void inint()
{
    int i,j;
    memset(dis,INF,sizeof(dis));
    if(!inin)   g.push_back(0);
    if(!ininin)  g.push_back(n-1);
    sort(g.begin(),g.end());

    for(i=0;i<g.size();i++)
    {
        dij(g[i]);
        for(j=0;j<g.size();j++)
            dis[i][j]=d[g[j]];
    }
}

int get(int cur)
{
   int i,j;
   int t=0;
   for(i=0;i<=k;i++)
     if(cur&(1<<i))
     {
        if(i==0&&inin) t++;
        if(i!=0&&i!=k) t++;
        if(i==k&&ininin) t++;
     }
     return t;
}

bool DP()
{
    int i,j;
    k=g.size()-1;

    memset(dp,INF,sizeof(dp));
    dp[1][0]=0;
    int len=1<<(k+1);

    for(int cur=1;cur<len;cur++)
        for(i=0;i<=k;i++)
       {
        if(!cur&(1<<i)) continue;
        if(dp[cur][i]>=INF) continue;
        for(int j=0;j<=k;j++)
        {
            if(cur&(1<<j)) continue;
            if(dis[i][j]>=INF) continue;
            int to=cur|(1<<j);
            dp[to][j]=min(dp[to][j],dp[cur][i]+dis[i][j]);
        }
    }

   memset(ans,INF,sizeof(ans));
   for(i=0;i<len;i++)
   {
       if(dp[i][k]>=INF) continue;
       int t=get(i);
       ans[t]=min(ans[t],dp[i][k]);
   }

   for(i=k+k;i>=0;i--)
      if(ans[i]<INF)
      {
          printf("Case %d: %d %d\n",++ca,i,ans[i]);
          return true;
      }
   return false;
}

int main()
{
   int i,j,t;
   ca=0;
   scanf("%d",&t);
   while(t--)
   {
       scanf("%d%d%d",&n,&m,&k);
       memset(a,INF,sizeof(a));
       inin=false;
       ininin=false;
       g.clear();
       int x;
       for(i=0;i<k;i++)
       {
           scanf("%d",&x);
           if(x==0) inin=true;
           if(x==n-1) ininin=true;
           g.push_back(x);
       }
       int u,v,len;
       while(m--)
       {
           scanf("%d%d%d",&u,&v,&len);
           if(a[u][v]>len) a[u][v]=len;
       }
        inint();
        if(!DP())
         printf("Case %d: Impossible\n",++ca);
   }
   return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值