【最短路】【spfa】CDOJ1647 酌贪泉而觉爽, 处涸辙以犹欢。

题意: 给你一个全为0的01串,问你能否通过一系列的变换,得到全为1的01串。 分析: 将每个01串看作一个点,每一个变换可以看作是一条有向边,现在问题可以转化 为找从“00..0”这个点到“11..1”这个点的最短路,那么可以使用spfa来解决这个问题。 对于每个CFT,建一条有向边,从si指向ti,权值为ti。然后跑spfa即可。

#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
queue<int>q;
int n,m,__next[100010],v[100010],e,first[(1<<20)+10],w[100010];
ll dis[(1<<20)+10];
bool inq[(1<<20)+10];
int trans(char T[]){
	int len=strlen(T);
	int res=0;
	for(int i=0;i<len;++i){
		res=res*2+T[i]-'0';
	}
	return res;
}
void AddEdge(int U,int V,int W){
	v[++e]=V;
	w[e]=W;
	__next[e]=first[U];
	first[U]=e;
}
void spfa(int s)
{
    memset(dis+1,0x7f,sizeof(dis));
    q.push(s); inq[s]=1; dis[s]=0;
    while(!q.empty())
      {
        int U=q.front();
        for(int i=first[U];i;i=__next[i])
          if(dis[v[i]]>dis[U]+(ll)w[i])
            {
              dis[v[i]]=dis[U]+(ll)w[i];
              if(!inq[v[i]])
                {
                  q.push(v[i]);
                  inq[v[i]]=1;
                }
            }
        q.pop(); inq[U]=0;
      }
}
int main(){
//	freopen("k.in","r",stdin);
	int x,y,z;
	char s[30];
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%s",s);
		x=trans(s);
		scanf("%s%d",s,&z);
		y=trans(s);
		AddEdge(x,y,z);
	}
	spfa(0);
	cout<<(dis[(1<<n)-1] < 100000000000001ll ? dis[(1<<n)-1] : -1)<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/6910410.html