题目链接:http://acm.uestc.edu.cn/#/problem/show/1647

题意:给你一个全为0的01串,问你能否通过一系列的变换,得到全为1的01串。

解法:将每个01串看作一个点,每一个变换可以看作是一条有向边,现在问题可以转化
为找从“00..0”这个点到“11..1”这个点的最短路,那么可以使用Dijkstra来解决这个问题。
对于每个CFT,建一条有向边,从si指向ti,权值为ti。然后运行Dijkstra即可。
复杂度O(ElogV) ,边数为10^5.

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2000010;
const int maxm = 400010;
const int inf = 0x3f3f3f3f;
typedef long long LL;
int n, m, edgecnt, head[maxn];
LL dis[maxn];
bool vis[maxn];
struct edge{
    int to, next;
    LL w;
    edge(){}
    edge(int to, LL w, int next):to(to),w(w),next(next){}
}E[maxm];
void init(){
    memset(head,-1,sizeof(head));
    edgecnt=0;
}
void add(int u, int v, LL w){
    E[edgecnt].to=v,E[edgecnt].w=w,E[edgecnt].next=head[u],head[u]=edgecnt++;
}
int Get(char *s){
    int ret = 0;
    int len = strlen(s);
    for(int i = 0; i < len; i++){
        ret = ret*2 + (s[i]-'0');
    }
    return ret;
}
void Dij(){
    priority_queue <pair<int,int>, vector<pair<int,int> >, greater<pair<int,int>> >pq;
    memset(vis,0,sizeof(vis));
    for(int i = 0; i <= (1<<n); i++) dis[i]=inf;
    dis[0]=0;
    pq.push(make_pair(dis[0],0));
    while(!pq.empty()){
        int u = pq.top().second;
        pq.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];~i;i=E[i].next){
            int v = E[i].to;
            if(dis[v]>dis[u]+E[i].w){
                dis[v]=dis[u]+E[i].w;
                pq.push(make_pair(dis[v],v));
            }
        }
    }
}
char s1[30], s2[30];
LL x;
int main()
{
    scanf("%d %d", &n, &m);
    init();
    for(int i=1; i<=m; i++){
        scanf("%s%s%lld", s1, s2, &x);
        int u = Get(s1);
        int v = Get(s2);
        add(u, v, x);
    }
    Dij();
    int en = (1<<n)-1;
    if(dis[en]==inf){
        printf("-1\n");
    }
    else{
        printf("%lld\n", dis[en]);
    }
    return 0;
}