ural 1500. Pass Licenses

1500. Pass Licenses

Time limit: 2.5 second
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  KN, 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


暴力枚举每个分类是否选择。但是,判断0-1是否连通时处理的不好很容易超时!个人感觉原因在于这题的边可能非常多!

第一种方法,存下所有边,然后并查集判连通,超时。

第二种,存所有边,然后dfs判连通,超时。

加优化,当现在枚举的已选择的分类个数,大于已知答案,则跳过,超时。

再加优化,不存储所有边,而改成存储每两个点间,能用的边有哪些种,用一个int做状态压缩。再dfs终于过了!


#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<cmath>
using namespace std;
const int maxn = 30 + 5;
const int INF = 1e9;
const double eps = 1e-6;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> P;
#define fi first
#define se second

int vis[maxn];
int G[maxn][maxn];

bool dfs(int pos, int use){
    if(pos == 1)
        return true;
    for(int i = 0;i < maxn;i++){
        if(!vis[i] && G[pos][i]&use){
            vis[i] = 1;
            if(dfs(i, use))
                return true;
        }
    }
    return false;
}

int main(){
    int k, n, m;
    while(scanf("%d%d%d", &k, &n, &m) != EOF){
        memset(G, 0, sizeof G);
        for(int i = 0;i < m;i++){
            int x, y, kind;
            scanf("%d%d%d", &x, &y, &kind);
            kind = 1 << kind;
            G[x][y] |= kind;
            G[y][x] = G[x][y];
        }
        int ans, Min = INF;
        int limit = 1<<k;
        for(int i = 1;i < limit;i++){
            memset(vis, 0, sizeof vis);
            vis[0] = 1;
            int cnt = 0;
            for(int j = 0;j < k;j++){
                if((1<<j)&i)
                    cnt++;
            }
            if(cnt < Min && dfs(0, i)){
                if(cnt < Min){
                    Min = cnt;
                    ans = i;
                }
            }
        }
        printf("%d\n", Min);
        for(int i = 0;i < k;i++){
            if(ans&(1<<i))
                printf("%d ", i);
        }
        puts("");
    }
    return 0;
}


你可能感兴趣的:(ural 1500. Pass Licenses)