Gym 101485 E Elementary Math 网络流 或者 二分图
题意:
输入一个n,后面输入n行,每一行两个数a、b。你可以对a、b进行三种操作:+、-、*
你需要保证对每一行a、b选取一个操作得到一个结果
你要保证这n行每一个式子选取的操作之后得到的结果都不一样。如果找不到就输出impossible
Sample Input 1
1 4
1 5
3 3
4 5
-1 -6
Sample Output
1 + 5 = 6
3 * 3 = 9
4 - 5 = -1
-1 - -6 = 5
Sample Input 2
2 4
-4 2
-4 2
-4 2
-4 2
Sample Output
impossible
题解:
网络流跑一边最大流就可以了
首先建一个汇点st,然后让st点和n个式子相连,把这n个式子看成一个点,然后一个式子对应三个结果,我们分别对着三个结果看成一个点,然后连线。之后把所有的结果点连接到一个尾点en
然后就是路径输出就行了,如果一个路径有流量,那么这个路径的流量信息肯定有改变,就判断这一点就可以输出路径
建图其实很简单,这里主要说一下不同网络流的复杂度
简单总结
FF算法: 利用dfs实现,时间复杂度O(V*E^2)
EK算法:利用bfs实现,时间复杂度O(V*E^2)
Dinic算法:递归实现,时间复杂度O(V^2*E)
SAP算法:时间复杂度O(V^2*E)但是加上弧优化和间隙优化之后时间复杂度非常可观
我以前认为点的数量肯定比边的数量小,所以dinic算法复杂度最小,所以就只记住了一个dinic算法
但是这一道题使用dinic算法就TLE了
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <queue> 5 #include <map> 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 using namespace std; 8 typedef long long ll; 9 const int maxn=8000; 10 queue<int> q; 11 int n,m,cnt,st,en,ans; 12 ll ref[10010],ra[2510],rb[2510]; 13 int head[maxn],dis[maxn],cur[maxn]; 14 map<ll,int> r; 15 struct edge 16 { 17 int v,next,c,flow; 18 } e[maxn<<2]; 19 void add_edge(int x,int y,int z) 20 { 21 e[cnt].v=y; 22 e[cnt].c=z; 23 e[cnt].flow=0; 24 e[cnt].next=head[x]; 25 head[x]=cnt++; 26 27 e[cnt].v=x; 28 e[cnt].c=0; 29 e[cnt].flow=0; 30 e[cnt].next=head[y]; 31 head[y]=cnt++; 32 } 33 int bfs() 34 { 35 mem(dis,0); 36 dis[st]=1; 37 queue<int>r; 38 r.push(st); 39 while(!r.empty()) 40 { 41 int x=r.front(); 42 r.pop(); 43 //printf("%d***\n",x); 44 for(int i=head[x]; i!=-1; i=e[i].next) 45 { 46 int v=e[i].v; 47 if(!dis[v] && e[i].c>e[i].flow) 48 { 49 //printf("%d***\n",v); 50 dis[v]=dis[x]+1; 51 r.push(v); 52 } 53 } 54 } 55 return dis[en]; 56 } 57 int dinic(int s,int limit) 58 { 59 if(s==en || !limit) return limit; 60 int ans=0; 61 for(int &i=cur[s]; i!=-1; i=e[i].next) 62 { 63 int v=e[i].v,feed; 64 if(dis[v]!=dis[s]+1) continue; 65 feed=dinic(v,min(limit,e[i].c-e[i].flow)); 66 if(feed) 67 { 68 e[i].flow+=feed; 69 e[i^1].flow-=feed; 70 limit-=feed; 71 ans+=feed; 72 if(limit==0) break; 73 } 74 } 75 if(!ans) dis[s]=-1; 76 return ans; 77 } 78 inline int rd() 79 { 80 int ret=0,f=1; 81 char gc=getchar(); 82 while(gc<'0'||gc>'9') 83 { 84 if(gc=='-') f=-f; 85 gc=getchar(); 86 } 87 while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); 88 return ret*f; 89 } 90 int main() 91 { 92 n=m=rd(),st=0; 93 int i,j; 94 memset(head,-1,sizeof(head)); 95 for(i=1; i<=n; i++) 96 { 97 ra[i]=rd(),rb[i]=rd(); 98 if(!r[ra[i]+rb[i]]) r[ra[i]+rb[i]]=++m,ref[m]=ra[i]+rb[i]; 99 if(!r[ra[i]-rb[i]]) r[ra[i]-rb[i]]=++m,ref[m]=ra[i]-rb[i]; 100 if(!r[ra[i]*rb[i]]) r[ra[i]*rb[i]]=++m,ref[m]=ra[i]*rb[i]; 101 add_edge(i,r[ra[i]+rb[i]],1); 102 add_edge(i,r[ra[i]-rb[i]],1); 103 add_edge(i,r[ra[i]*rb[i]],1); 104 add_edge(st,i,1); 105 } 106 en=m+1; 107 for(i=n+1; i<=m; i++) add_edge(i,en,1); 108 int ans=0; 109 while(bfs()) 110 { 111 for(int i=0; i<=en+1; ++i) 112 { 113 cur[i]=head[i]; 114 } 115 ans+=dinic(st,1); 116 } 117 if(ans!=n) 118 { 119 printf("impossible"); 120 return 0; 121 } 122 for(i=1; i<=n; i++) 123 { 124 for(j=head[i]; j!=-1; j=e[j].next) 125 { 126 if(e[j].flow>0 && e[j].v!=st) 127 { 128 if(ref[e[j].v]==ra[i]+rb[i]) 129 printf("%lld + %lld = %lld\n",ra[i],rb[i],ra[i]+rb[i]); 130 else if(ref[e[j].v]==ra[i]-rb[i]) 131 printf("%lld - %lld = %lld\n",ra[i],rb[i],ra[i]-rb[i]); 132 else if(ref[e[j].v]==ra[i]*rb[i]) 133 printf("%lld * %lld = %lld\n",ra[i],rb[i],ra[i]*rb[i]); 134 break; 135 } 136 } 137 } 138 return 0; 139 }
AC代码:
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <map> using namespace std; typedef long long ll; queue<int> q; int n,m,cnt,st,en,ans; ll ref[10010],ra[2510],rb[2510]; int to[100000],nxt[100000],head[10010],val[100000],dis[10010]; map<ll,int> r; inline void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,nxt[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,nxt[cnt]=head[b],head[b]=cnt++; } int dfs(int x,int mf) { if(x==en) return mf; int i,k,temp=mf; for(i=head[x]; i!=-1; i=nxt[i]) if(dis[to[i]]==dis[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) dis[to[i]]=0; temp-=k,val[i]-=k,val[i^1]+=k; if(!temp) break; } return mf-temp; } int bfs() { while(!q.empty()) q.pop(); memset(dis,0,sizeof(dis)); q.push(st),dis[st]=1; int i,u; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u]; i!=-1; i=nxt[i]) if(!dis[to[i]]&&val[i]) { dis[to[i]]=dis[u]+1; if(to[i]==en) return 1; q.push(to[i]); } } return 0; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') { if(gc=='-') f=-f; gc=getchar(); } while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } int main() { n=m=rd(),st=0; int i,j; memset(head,-1,sizeof(head)); for(i=1; i<=n; i++) { ra[i]=rd(),rb[i]=rd(); if(!r[ra[i]+rb[i]]) r[ra[i]+rb[i]]=++m,ref[m]=ra[i]+rb[i]; if(!r[ra[i]-rb[i]]) r[ra[i]-rb[i]]=++m,ref[m]=ra[i]-rb[i]; if(!r[ra[i]*rb[i]]) r[ra[i]*rb[i]]=++m,ref[m]=ra[i]*rb[i]; add(i,r[ra[i]+rb[i]],1); add(i,r[ra[i]-rb[i]],1); add(i,r[ra[i]*rb[i]],1); add(st,i,1); } en=m+1; for(i=n+1; i<=m; i++) add(i,en,1); while(bfs()) ans+=dfs(st,1<<30); if(ans!=n) { printf("impossible"); return 0; } for(i=1; i<=n; i++) { for(j=head[i]; j!=-1; j=nxt[j]) { if(!val[j]) { if(ref[to[j]]==ra[i]+rb[i]) printf("%lld + %lld = %lld\n",ra[i],rb[i],ra[i]+rb[i]); else if(ref[to[j]]==ra[i]-rb[i]) printf("%lld - %lld = %lld\n",ra[i],rb[i],ra[i]-rb[i]); else if(ref[to[j]]==ra[i]*rb[i]) printf("%lld * %lld = %lld\n",ra[i],rb[i],ra[i]*rb[i]); } } } return 0; }
二分图题解:
就是把n个式子看成n个点,把n个式子对应的三个结果看成3*n个点
二分图匹配就行
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <map> using namespace std; typedef long long ll; const int maxn=7500+10; const int INF=0x3f3f3f3f; const long long ll_INF=0x3f3f3f3f3f3f3f3fll; ll match[maxn],visit[maxn],n,m,grap[2505][maxn],link[maxn]; map<ll,ll>r; ll dfs_solve(ll x) { for(ll i=1; i<=m; ++i) { //printf("%d***\n",grap[x][i]); if(grap[x][i] && !visit[i]) { visit[i]=1; //printf("%d %d %d****\n",x,i,match[i]); if(match[i]==0 || dfs_solve(match[i])) { match[i]=x; link[x]=i; return 1; } } } return 0; } ll hungran() { memset(match,0,sizeof(match)); ll sum=0; for(ll i=1; i<=n; ++i) { memset(visit,0,sizeof(visit)); sum+=dfs_solve(i); } return sum; } ll que[maxn]; struct shudui { ll a,b; } w[2505]; int main() { scanf("%lld",&n); m=0; for(ll i=1; i<=n; ++i) { ll a,b; scanf("%lld%lld",&a,&b); w[i].a=a; w[i].b=b; if(r[a*b]==0) { r[a*b]=++m; que[m]=a*b; } grap[i][r[a*b]]=1; if(r[a+b]==0) { r[a+b]=++m; que[m]=a+b; } grap[i][r[a+b]]=1; if(r[a-b]==0) { r[a-b]=++m; que[m]=a-b; } grap[i][r[a-b]]=1; } ll ans=hungran(); //printf("%lld***%lld %lld\n",ans,n,m); if(ans!=n) { printf("impossible\n"); return 0; } for(ll i=1; i<=n; ++i) { ll x=que[link[i]]; ll a=w[i].a; ll b=w[i].b; //printf("%lld %lld %lld\n",a,b,x); if(x==a+b) printf("%lld + %lld = %lld\n",a,b,x); else if(x==a-b) printf("%lld - %lld = %lld\n",a,b,x); else if(x==a*b) printf("%lld * %lld = %lld\n",a,b,x); } return 0; } /* 4 1 5 3 3 4 5 -1 -6 */