链接:https://www.oj.swust.edu.cn/oj/problem/show/1747
分析:最多只有20个错误,肯定位操作压缩一下,然后每种状态看做一个点,满足条件的两点连边,求从全错到全对的最短路径即可。一开始疯狂T,后面把模板里加边去掉,直接在增广时判断是否有边,4ms过了。。。以后能不用加边的尽量不用,效率太低了。。
1 #include<iostream> 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 const int maxn=1<<20,INF=1e9; 8 struct Edge{ 9 int to,len; 10 Edge(int v,int l):to(v),len(l){} 11 }; 12 struct Patch{ 13 int b1,b2,f1,f2,t; 14 }p[105]; 15 int n,m; 16 int dis[maxn]; 17 bool inq[maxn]; 18 int spfa(){ 19 memset(inq,0,sizeof(inq)); 20 for(int i=0;i<(1<<n);i++)dis[i]=INF; 21 int u=(1<<n)-1; 22 dis[u]=0; 23 queue<int> Q; 24 Q.push(u); 25 inq[u]=true; 26 while(!Q.empty()){ 27 u=Q.front();Q.pop(); 28 inq[u]=false; 29 for(int i=0;i<m;i++){ 30 if((p[i].b1&u)==p[i].b1&&(p[i].b2&u)==0){ 31 int v=u&(~p[i].f1)|p[i].f2; 32 if(v==u)continue; 33 if(dis[v]>dis[u]+p[i].t){ 34 dis[v]=dis[u]+p[i].t; 35 if(!inq[v]){ 36 Q.push(v);inq[v]=true; 37 } 38 } 39 } 40 } 41 } 42 return dis[0]; 43 } 44 void read(){ 45 string str; 46 for(int i=0;i<m;i++){ 47 int k=1; 48 scanf("%d",&p[i].t); 49 cin>>str; 50 for(int j=0;j<str.length();j++){ 51 switch(str[j]){ 52 case '+':p[i].b1^=k;break; 53 case '-':p[i].b2^=k;break; 54 } 55 k<<=1; 56 } 57 cin>>str; 58 k=1; 59 for(int j=0;j<str.length();j++){ 60 switch(str[j]){ 61 case '+':p[i].f2^=k;break; 62 case '-':p[i].f1^=k;break; 63 } 64 k<<=1; 65 } 66 } 67 } 68 int main(){ 69 // freopen("e:\in.txt","r",stdin); 70 scanf("%d%d",&n,&m); 71 read(); 72 int ans=spfa(); 73 if(ans==INF)printf("0 "); 74 else printf("%d ",ans); 75 return 0; 76 } 77 78 /* 79 能不记录图尽量不记录,效率上差超级多!!! 80 用vector记邻接链表,T掉了。。改为不记录的,4ms过。。 81 */