bzoj4429: [Nwerc2015] Elementary Math小学数学
先把所有可能的答案算出来,每个算式一个点,每个结果一个点,然后如果一个算式能算出一个结果,那么就连一条边
然后跑匈牙利,没有完美匹配就是impossible
每个算式最多有3个结果,所以边数是O(n)的,所以匈牙利的复杂度就是O(n^2)的
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <map> #define ll long long #define N 77777 #define M 77777 using namespace std; inline int read(){ int ret=0;char ch=getchar(); bool flag=0; while (ch<'0'||ch>'9'){ flag=ch=='-'; ch=getchar(); } while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return flag?-ret:ret; } struct edge{ int adj,next,op; edge(){} edge(int _adj,int _next,int _op):adj(_adj),next(_next),op(_op){} } e[M]; int n,g[N],m; void AddEdge(int u,int v,int op){ e[++m]=edge(v,g[u],op);g[u]=m; } int fx[N],fy[N],fop[N]; bool vis[N/3]; int dfs(int u){ if (vis[u]) return 0; vis[u]=1; for (int i=g[u];i;i=e[i].next){ int v=e[i].adj; if (!fy[v]||dfs(fy[v])){ fy[v]=u;fx[u]=v;fop[u]=e[i].op; return 1; } } return 0; } char ch[3]={'+','-','*'}; inline ll calc(ll x,ll y,int op){ if (op==0) return x+y; else if (op==1) return x-y; else return x*y; } ll a[N],b[N]; map<ll,int> s;int cnt; int main(){ n=read(); s.clear(); map<ll,int>::iterator it; ll tmp; for (int i=1;i<=n;++i){ a[i]=read();b[i]=read(); for (int op=0;op<3;++op){ it=s.find(calc(a[i],b[i],op)); if (it==s.end()) s.insert(make_pair(calc(a[i],b[i],op),++cnt)); AddEdge(i,s.find(calc(a[i],b[i],op))->second,op); } } int tot=0; memset(fx,0,sizeof(fx)); memset(fy,0,sizeof(fy)); for (int i=1;i<=n;++i)if (!fx[i]){ memset(vis,0,sizeof(vis)); tot+=dfs(i); } if (tot<n){puts("impossible");return 0;} for (int i=1;i<=n;++i) printf("%lld %c %lld = %lld\n",a[i],ch[fop[i]],b[i],calc(a[i],b[i],fop[i])); return 0; }