zoukankan      html  css  js  c++  java
  • ural 1500 Pass Licenses (状态压缩+dfs)

    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

    inputoutput
    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
     
     
    题意:给出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
    ",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;
    }
  • 相关阅读:
    主席树学习记录
    P1072 Hanson 的趣味题 题解
    好文章收集
    计算几何专题
    小问题
    CSP-S2020题解
    上下界网络流
    想到的无法解决的点子
    省选联考2020组合数问题
    省选数学复习
  • 原文地址:https://www.cnblogs.com/someblue/p/3940841.html
Copyright © 2011-2022 走看看