1500. Pass Licenses
Time limit: 2.5 second
Memory limit: 64 MB
Memory limit: 64 MB
A New Russian Kolyan believes that to spend his time in traffic jams is below his dignity. This is why he had put an emergency flashlight upon the roof of his Hummer and had no problems until a recent decision of the city administration. Now each street of the city belongs to one or several categories, and a driver must have a separate license in order to use an emergency flashlight in the streets of each category. If a street belongs to several categories, it is sufficient to have a license only for one of these categories. For each category, a license is issued by a separate city official. Although these officials are different, they accept bribes of the same amount for giving a license. Help Kolyan to find a way from his home to work such that he can go this way with his flashlight turned on and having spent the minimal amount of money for bribes.
Input
The input contains the street plan in the following format. There are integers K, N, and M in the first line, where K is the number of street categories (1 ≤ K ≤ 20), N is the number of crossroads (2 ≤ N ≤ 30), and M is the number of descriptions of street segments between crossroads.
Each of the next M lines describes a street segment by three integers V1 V2 C, where V1 and V2 are the numbers of the crossroads limiting this segment, and C is its category. Crossroads are numbered from 0 to N – 1, categories are numbered from 0 to K – 1. For any pair of crossroads no two segments of the same category connect these crossroads.
Output
Output in the first line the minimal number of licenses necessary for going from the crossroad 0 (Kolyan's home) to the crossroad 1 (Kolyan's work) with an emergency flashlight turned on.
In the second line, give the list of categories for which licenses must be obtained. The numbers should be separated with spaces. It is guaranteed that such list is always exist.
Sample
input | output |
---|---|
3 3 3 0 2 0 0 2 1 1 2 2 |
2 0 2 |
Problem Author: Magaz Asanov, Alexander Mironenko, Anton Botov, Evgeny Krokhalev
Problem Source: Quarter-Final of XXXI ACM ICPC - Yekaterinburg - 2006
Problem Source: Quarter-Final of XXXI ACM ICPC - Yekaterinburg - 2006
题意:给出k种通行证,n个点,m条边。每条边都会属于一个或几个通行证,能通过这条边的条件是有至少一个通行证。求最少通行证数量使得能从0点出发到1点。
思路:每条边按照通行证可以写成一个状态cost,例如有通行证1 3可以表示为1010,然后对于机主通行证的状态S,那能通过这条边的条件就是 S&cost != 0 。所以枚举每一个机主状态,dfs一遍判断能否到达终点就ok了
妈蛋这么水的题哇了那么多次,搞了半个钟原来是for循环结束条件的问题,我擦好粗心。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <map> #include <utility> #include <queue> #include <stack> #define set(s,x) (s|=(1<<x)) #define test(s,x) (s&(1<<x)) using namespace std; const int INF=1<<30; const double eps=1e-6; const int N = 35; int cost[N][N]; int k,n,m; bool vis[N]; bool dfs(int s,int u) { if(u==1) return 1; if(vis[u]) return 0; vis[u]=1; for(int v=0;v<n;v++) { if(u==v) continue; if((cost[u][v]&s)) if(dfs(s,v)) return 1; } return 0; } int getcnt(int s) { int i,cnt=0; for(i=0;i<k;i++) if(test(s,i)) cnt++; return cnt; } void print(int s) { for(int i=0;i<k;i++) if(test(s,i)) printf("%d ",i); puts(""); } void run() { memset(cost,0,sizeof(cost)); int u,v,w; while(m--) { scanf("%d%d%d",&u,&v,&w); if(u==v) continue; set(cost[u][v],w); set(cost[v][u],w); } int ans, anst = k+1; for(int i=1;i<(1<<k);i++) { memset(vis,0,sizeof(vis)); int tmp = getcnt(i); if(tmp>=anst) continue; if(dfs(i,0)) { anst = tmp; ans = i; } } printf("%d\n",anst); print(ans); } int main() { #ifdef LOCAL freopen("case.txt","r",stdin); #endif while(scanf("%d%d%d",&k,&n,&m)!=EOF) run(); return 0; }