spoj 179. Word equations (代码等式)
经典问题,并查集实现
题意:略,几题的分析也略,黑书81页有分析另外网上也能找到很多
注意一些特判的情况就不回WA,另外题意描述确实不够准确,稍后更新具体的分析部分
1.可能出现两个等式长度不等的情况,直接判为无解
2.对于k=0,即没有英文单词只有01的时候只要比较这两个串是否相同即可,相同结果为1,不同为0,其实不需要特判也行,但是我采用了特判
3.不同字母可以用相同的01表示,好像a,b,按理说是不同的字母应该有不同的表示,不能一样,但是是允许的,即可以同时为某个01组合
4.没用上的英文单词也需要计算在内
好像
3
2 2 2
2
ab
2
ab
答案是多少?应该是2^2*2^2=16?,虽然c没有用上,但是也要计算在内,即16*2^2 = 64,因为c取任何值都不影响等式
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; const int N = 10010; const int M = 30; const int MAX = 11111111; vector<int>A,B; char str1[N],str2[N]; int n,tot,num[M],last[M],ans[MAX],fa[MAX]; void cal_and_print(int m) { int len; ans[0] = 2; len = 0; for(int i=1; i<m; i++) { int c = 0; for(int k=0; k<=len; k++) { ans[k] = ans[k] * 2 + c; c = ans[k] / 10; ans[k] %= 10; } if(c) ans[++len] = c; } for(int i=len; i>=0; i--) printf("%d",ans[i]); printf("\n"); } int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]); } void Union(int x , int y) { if(y < 2) swap(x,y); fa[y] = x; } int solve() { int count = tot-1; int size = A.size(); for(int i=0; i<=tot; i++) fa[i] = i; //初始化并查集 for(int i=0; i<size; i++) { int u = A[i] , v = B[i]; int ance_u = find(u); int ance_v = find(v); if(ance_u == ance_v) continue; if(ance_u + ance_v == 1) return -1; Union(ance_u , ance_v); count--; } // for(int i=0; i<=tot; i++) printf("%d ",fa[i]); cout << endl; // printf("count = %d\n",count); return count; } int main() { int cas,m; scanf("%d",&cas); while(cas--) { A.clear(); B.clear(); memset(last,0,sizeof(last)); memset(num,0,sizeof(num)); scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&num[i]); last[0] = 1; for(int i=1; i<=n; i++) last[i] = last[i-1] + num[i]; tot = last[n]; //包括01在内一共产生了[0,tot]编号的变量,而个数应该是tot+1 scanf("%d%s",&m,str1); for(int i=0; i<m; i++) { if(str1[i]>='a' && str1[i]<='z') { int c = str1[i] - 'a' + 1; for(int k=last[c-1]+1; k<=last[c]; k++) A.push_back(k); } else A.push_back(str1[i]-'0'); } scanf("%d%s",&m,str2); for(int i=0; i<m; i++) { if(str2[i]>='a' && str2[i]<='z') { int c = str2[i] - 'a' + 1; for(int k=last[c-1]+1; k<=last[c]; k++) B.push_back(k); } else B.push_back(str2[i]-'0'); } if( A.size() != B.size() ) { puts("0"); continue; } //两个等式的长度都不同肯定不相等 if(n==0) { if(!strcmp(str1,str2)) puts("1"); else puts("0"); continue; } int res = solve(); if(res == -1) { puts("0"); continue; } if(res == 0) { puts("1"); continue; } //返回0个等价类说明只有唯一解 cal_and_print(res); //高精度计算,并且打印答案 } return 0; }