ZOJ Problem Set - 2949 Coins of Luck
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #define LL long long #define INF 1e9 #define INF 1e-9 using namespace std; const int maxn=1234; int n; double ai[maxn][maxn]; double bi[maxn][maxn*2]; double ans[maxn]; void init() { memset(ai,0,sizeof(ai)); memset(bi,0,sizeof(bi)); ai[0][0]=1; for(int i=1; i<=2*1000; i++) { //w for(int j=1; j<=i; j++) { int w=j; int b=i-j; if(w<=1000&&b<1000) { ai[w][b]+=(ai[w-1][b]/2.0); if(w>b) bi[w][w+b]+=(ai[w-1][b]/2.0); } } //b for(int j=1; j<=i; j++) { int w=i-j; int b=j; if(b<=1000&&w<1000) { ai[w][b]+=(ai[w][b-1]/2.0); if(b>w) bi[b][w+b]+=(ai[w][b-1]/2.0); } } } for(int i=1; i<=1000; i++) { double tm=0; for(int j=0; j<=i*2; j++) { tm+=bi[i][j]*j; } ans[i]=tm; } } void play() { scanf("%d",&n); printf("%.2f\n",ans[n]); } int T; int main() { init(); scanf("%d",&T); while(T--) { play(); } // cout << "Hello world!" << endl; return 0; } /* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #include <set> #define LL long long #define INF 1e9 #define INF 1e-9 using namespace std; const int maxn=1234; int n; double ai[maxn][maxn]; double ans[maxn]; void init() { memset(ai,0,sizeof(ai)); for(int i=0; i<=1000; i++) { for(int j=0; j<=1000; j++) { int w=i; int b=j; if(w==0&&b==0)ai[i][j]=1; else { if(w!=0) { ai[w][b]+=(ai[w-1][b]/2.0); } if(b!=0) { ai[w][b]+=(ai[w][b-1]/2.0); } if(w>b) { ans[w]+=(ai[w-1][b]/2.0)*(w+b); } if(b>w) { ans[b]+=(ai[w][b-1]/2.0)*(w+b); } } } } } void play() { scanf("%d",&n); printf("%.2f\n",ans[n]); } int T; int main() { init(); scanf("%d",&T); while(T--) { play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 2475 Benny's Compiler
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=123; //bool isC[maxn][maxn]; vector<int> V[maxn]; int n,E; void init(){ for(int i=1;i<=100;i++)V[i].clear(); int u,v; // memset(isC,0,sizeof(isC)); for(int i=1;i<=n;i++){ scanf("%d%d",&u,&v); if(u==v)continue; V[u].push_back(v); // isC[u][v]=1; } /*for(int k=1;k<=100;k++){ for(int i=1;i<=100;i++){ for(int j=1;j<=100;j++){ if(isC[i][k]&&isC[k][j])isC[i][j]=1; } } }*/ scanf("%d",&E); } bool flag; bool vis[maxn]; void DFS(int now){ if(flag)return; for(int i=0;i<V[now].size();i++){ int v=V[now][i]; if(vis[v]){ flag=1; return; } vis[v]=1; DFS(v); vis[v]=0; } } void play(){ flag=0; memset(vis,0,sizeof(vis)); vis[E]=0; DFS(E); if(flag)printf("No\n"); else printf("Yes\n"); } int main() { while(scanf("%d",&n)!=EOF){ if(n<0)break; init(); play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 2706 Thermal Death of the Universe
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <map> #include <stack> #include <queue> #include <set> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=3*12345; struct he { int l,r; LL lazy; LL sum; } Sky[maxn*4]; void BuildTree(int l,int r,int now) { Sky[now].l=l; Sky[now].r=r; Sky[now].lazy=0; Sky[now].sum=0; if(l==r)return; int mid=(l+r)/2; BuildTree(l,mid,now*2); BuildTree(mid+1,r,now*2+1); } void Push(int now) { if(Sky[now].lazy==0)return; int nl=Sky[now].l; int nr=Sky[now].r; if(nl==nr)return; LL v=Sky[now].lazy; int mid=(nl+nr)/2; Sky[now*2].lazy=v; Sky[now*2].sum=v*(mid-nl+1); Sky[now*2+1].lazy=v; Sky[now*2+1].sum=v*(nr-mid); Sky[now].lazy=0; } void Update(int l,int r,int now,LL val) { if(Sky[now].l==l&&Sky[now].r==r) { Sky[now].lazy=val; Sky[now].sum=val*(r-l+1); return; } int mid=(Sky[now].l+Sky[now].r)/2; if(r<=mid) { Update(l,r,now*2,val); } else if(l>mid) { Update(l,r,now*2+1,val); } else { Update(l,mid,now*2,val); Update(mid+1,r,now*2+1,val); } Sky[now].sum=Sky[now*2].sum+Sky[now*2+1].sum; } LL Query(int l,int r,int now) { if(Sky[now].l==l&&Sky[now].r==r) { return Sky[now].sum; } int mid=(Sky[now].l+Sky[now].r)/2; LL o1=0; LL o2=0; Push(now); if(r<=mid) { o1=Query(l,r,now*2); } else if(l>mid) { o2=Query(l,r,now*2+1); } else { o1=Query(l,mid,now*2); o2=Query(mid+1,r,now*2+1); } return o1+o2; } int n,m; LL Calc(LL val, int dn, bool isok) { if(val>=0){ int p=val/dn; if(isok)return p+1; else return p; } else{ int p=val/dn; if(isok)return p; else return p-1; } } void init() { BuildTree(1,n,1); int t; LL sum=0; for(int i=1; i<=n; i++) { scanf("%d",&t); Update(i,i,1,t); sum+=t; } int l,r; while(m--) { scanf("%d%d",&l,&r); if(l>r)swap(l,r); LL p=Query(l,r,1); int len=(r-l+1); if(p%len==0) { Update(l,r,1,p/len); } else { if(Sky[1].sum<=sum) { Update(l,r,1,Calc(p,r-l+1,1)); } else { Update(l,r,1,Calc(p,r-l+1,0)); } } } } void play() { bool first=1; for(int i=1; i<=n; i++) { LL p=Query(i,i,1); if(!first)printf(" "); first=0; printf("%lld",p); } printf("\n"); printf("\n"); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 3856 Goldbach
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> #include <map> #include <stack> #include <vector> #include <set> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=8*12345; bool isP[maxn]; int n; const int MOD=1000000007; LL ai[2][maxn]; LL sum[maxn]; int bi[maxn]; int E; void init() { memset(isP,0,sizeof(isP)); isP[1]=1; for(int i=2; i<=80000; i++) { if(isP[i])continue; for(int j=i+i; j<=80000; j+=i) { isP[j]=1; } } E=0; for(int i=1; i<=80000; i++) { if(isP[i]) { isP[i]=0; continue; } isP[i]=1; E++; bi[E]=i; } memset(ai,0,sizeof(ai)); for(int i=1; i<=E; i++) { for(int j=i; j<=E; j++) { LL t1=bi[i]; LL t2=bi[j]; if(t1+t2<=80000) { ai[0][t1+t2]=(ai[0][t1+t2]+1); } if(t1*t2<=80000) { ai[1][t1*t2]=(ai[1][t1*t2]+1); } } } } int k; void play() { sum[k]=0; sum[k]+=isP[k]; LL p=(ai[0][k]+ai[1][k]); sum[k]=(sum[k]+p)%MOD; LL n1=0; LL n2=0; for(int i=1; i<=E; i++) { if(bi[i]>=k)break; int t=k-bi[i]; if(t%2==0) { int q=t/2; if(q==bi[i]) { n1+=2; } else n1+=isP[q]; } n1=(n1+ai[0][t]); n2=(n2+ai[1][t]); int q=k%bi[i]; if(q==0) { t=k/bi[i]; int q=sqrt(t); if(q*q==t) { if(q==bi[i]) { n1+=2; } else n1+=isP[q]; } n1=(n1+ai[1][t]); } } n1=n1/3; sum[k]=(sum[k]+n1); sum[k]=(sum[k]+n2); printf("%lld\n",sum[k]); } int main() { init(); while(scanf("%d",&k)!=EOF) { play(); } return 0; }
ZOJ Problem Set - 2058 The Archaeologist's Trouble II
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1058
题意:就是给你n行,第i行有i个字符,字符可以是'@','*','?',其中需要确定?的值,根据题目的4中限制,使得得到@最多,或则@最少,输出这个值。
分析:看一下这4种类型可以知道,假设为2行,第一行一个字符,第二行两个,所以我们可以知道无论第一行是什么,第二行都必须是@*或则*@,这样的话我们就知道,假设在第k行,有k个字符,如果第j个字符是@,那么第j-1是*,j+1也是*,然后根据j-1和j+1可以继续第k行剩下的数据。所以,假设第k行都是?,那么如果k%2==0,那么@和*只能平分。反之,设得到@最多为MAX,最少为MIN,那么,MAX多加个1,因为有k/2个*和k/2+1个@,MIN 的话就是k/2个@和k/2+1个*。如果第k行第i个是*,那么可知包含*的话,前面有i个字符,后面有af=k-i+1个字符,那么我们就可以知道MAX和MIN就都得有i/2个和af/2个,因为第i个是*,所以不用管是否奇偶。反之,一样MAX和MIN就都得有i/2个和af/2个,但是这里就得再考虑,如果i是奇数,那么我们得再加个1,因为i也是,如果af是奇数,同理,但是我们这里多记了1次i这个位置,所以都要减1。最后输出MAX和MIN就好了,啪啪啪就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=123; char ch[maxn]; int n; int MAX,MIN; void init() { MAX=0; MIN=0; for(int i=1; i<=n; i++) { scanf("%s",ch+1); bool flag=1; for(int j=1; j<=i; j++) { int af=i-j+1; if(ch[j]=='*') { flag=0; } if(ch[j]=='@') { if(j%2==1) { MAX++; MIN++; } if(af%2==1) { MAX++; MIN++; } MAX-=1; MIN-=1; flag=0; } if(!flag) { MAX+=j/2; MIN+=j/2; MAX+=af/2; MIN+=af/2; break; } } if(flag) { MAX+=i/2; MIN+=i/2; if(i%2==1)MAX++; } } } void play() { printf("%d %d\n",MAX,MIN); } int main() { while(scanf("%d",&n)&&n>0) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 2013 Labyrinth
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1013
题意:起先看的很迷糊啊。就是给你C*R的矩阵,然后矩阵里面是#(不可走)或.(可走),然后Input最后一句话每两个点之间最多正好就一条路,所以说路径不包含圈,所以是棵树,然后Output说输出两个点之间最长的长度是多少。
分析:知道题意的话就很简单了。可以用树形DP ,假设当前的节点为fa,如果它没有子节点,那么它就是叶子节点,那么直接返回1,如果它有一个子节点,那么最长就是子节点返回的值,用这个值更新最大值,然后返回最大值+1到fa的父节点,如果它有多余两个子节点。那么从它的子节点选择2个最大子节点,然后相加,更新最大值,再把最大值的一个子节点+1返回到fa的父节点,这样最后的最大值就是我们要求的最大路径了。啪啪啪就可以AC了。
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <map> #include <stack> #include <queue> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=1234; bool ai[maxn][maxn]; int T; int n,m; char ch[maxn]; void init() { scanf("%d%d",&m,&n); memset(ai,0,sizeof(ai)); for(int i=1; i<=n; i++) { scanf("%s",ch+1); for(int j=1; j<=m; j++) { if(ch[j]=='.')ai[i][j]=1; } } } bool cmp(int a,int b) { return a>b; } bool vis[maxn][maxn]; int MAX; int c1[]= {1,0,-1,0}; int c2[]= {0,1,0,-1}; int DFS(int x,int y) { int l1=-1,l2=-1; for(int i=0; i<4; i++) { int nx=x+c1[i]; int ny=y+c2[i]; if(!ai[nx][ny])continue; if(vis[nx][ny])continue; vis[nx][ny]=1; int q=DFS(nx,ny); if(l1==-1){ l1=q; } else{ if(q>l1){ l2=l1; l1=q; } else if(q>l2){ l2=q; } } } if(l1==-1) { return 1; } if(l2==-1) { MAX=max(MAX,l1); return l1+1; } MAX=max(MAX,l1+l2); return l1+1; } void play() { MAX=0; memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(!vis[i][j]) { vis[i][j]=1; if(!ai[i][j])continue; DFS(i,j); } } } printf("Maximum rope length is %d.\n",MAX); } int main() { scanf("%d",&T); while(T--) { init(); play(); } //cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 2029 The Intervals
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2029
题意:就是给你n个数,和m个查询,每个查询有个数q.从n个数选两个数,假设为a,b(a<b),使得q在区间[a,b)内。并且要求这个b-a最小。
分析:起先要是b-a最小又要包含t。我们可以将n个数排序,然后取两个数a,b,使得,a<=t<b,并且a和b越接近越好,为什么呢?因为越接近的话b-a就越小,因为我们排了序。然后具体a和b我们可以二分查找位置,然后特殊情况稍微处理一下就可以了,最后啪啪啪就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; vector<int> V; int n,m; void init() { V.clear(); int u; for(int i=1; i<=n; i++) { scanf("%d",&u); V.push_back(u); } sort(V.begin(),V.end()); } void play() { int t; while(m--) { scanf("%d",&t); int pos1=lower_bound(V.begin(),V.end(),t)-V.begin(); int pos2=upper_bound(V.begin(),V.end(),t)-V.begin(); if(pos1==n||pos2==n) { printf("no such interval\n"); continue; } if(pos1!=pos2) { printf("[%d,%d)\n",V[pos1],V[pos2]); continue; } if(pos1==0) { printf("no such interval\n"); continue; } printf("[%d,%d)\n",V[pos1-1],V[pos1]); } printf("\n"); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 3890 Wumpus
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3890
题意:有个人站在(0,0)位置,然后给你n*n的地图,其中地图中有黄金,怪物,坑,平地,因为题目简化了,坑不能进,怪物的地方不能进,黄金只有1块。人物的动作可以是转向,向前,挖金子,从(0,0)点出来,其中每个动作要花费10点的值,黄金值1000点值。求出来之后最大的值是多少.
分析:一看n<=20,且方向就只有4个,那么可以建立vis[20][20][4]的数组进行BFS模拟。
(1)由于数据非常小,所以我考虑到一点事情,就是如果黄金在sx,sy上,然后我们到达sx,sy,方向为1的值和到达sx,sy方向为2的值相同,然后从1到(0,0)比从2到(0,0)慢,那么如果我们到达1的时候就结束BFS,那么答案就错了,所以我是枚举到达sx,sy四个方向的值,然后再从这四个方向继续BFS回到(0,0),然后求出最小值就好,其中一些细节不符合条件的直接输出-1就好。虽然代码有点长,但是也不是特边复杂
(2)可以直接打标记,就是假设黄金在sx,sy,如果到了sx,sy,那么直接标记拿到了黄金,最后到了(0,0)之后,如果拿到了黄金那么就是最优值,这样代码就边的比较短了
最后啪啪啪就可以AC了。
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; struct he { int x,y,d,val; }; const int maxn=2*12; int ai[maxn][maxn]; bool vis[maxn][maxn][5]; int n,T; int ex,ey; void init() { scanf("%d",&n); memset(ai,0,sizeof(ai)); for(int i=0; i<=n; i++)ai[0][i]=ai[i][0]=ai[n+1][i]=ai[i][n+1]=2; int u,v,w; while(scanf("%d%d%d",&u,&v,&w)!=EOF&&u!=-1) { v++; w++; if(u==3) { ex=v; ey=w; } ai[v][w]=u; } } pair<int,int> calD(int d,int x,int y) { if(d==1)return make_pair(x+1,y); if(d==2)return make_pair(x,y+1); if(d==3)return make_pair(x-1,y); if(d==4)return make_pair(x,y-1); } int BFS1(int dd) { memset(vis,0,sizeof(vis)); queue<he> Q; Q.push((he) { 1,1,1,0 }); vis[1][1][1]=1; while(!Q.empty()) { he now=Q.front(); Q.pop(); int nx=now.x; int ny=now.y; int nd=now.d; int nv=now.val; if(ai[nx][ny]==3&&nd==dd) { return nv; } pair<int,int> need=calD(nd,nx,ny); int x=need.first; int y=need.second; if(ai[x][y]!=1&&ai[x][y]!=2&&!vis[x][y][nd]) { vis[x][y][nd]=1; Q.push((he) { x,y,nd,nv+10 }); } int d=nd+1; if(d==5)d=1; if(!vis[nx][ny][d]) { vis[nx][ny][d]=1; Q.push((he) { nx,ny,d,nv+10 }); } d=nd-1; if(d==0)d=4; if(!vis[nx][ny][d]) { vis[nx][ny][d]=1; Q.push((he) { nx,ny,d,nv+10 }); } } return -1; } int BFS2(int x1,int y1,int dd) { memset(vis,0,sizeof(vis)); vis[x1][y1][dd]=1; queue<he> Q; Q.push((he) { x1,y1,dd,0 }); while(!Q.empty()) { he now=Q.front(); Q.pop(); int nx=now.x; int ny=now.y; int nd=now.d; int nv=now.val; if(nx==1&&ny==1) { return nv; } pair<int,int> need=calD(nd,nx,ny); int x=need.first; int y=need.second; if(ai[x][y]!=1&&ai[x][y]!=2&&!vis[x][y][nd]) { vis[x][y][nd]=1; Q.push((he) { x,y,nd,nv+10 }); } int d=nd+1; if(d==5)d=1; if(!vis[nx][ny][d]) { vis[nx][ny][d]=1; Q.push((he) { nx,ny,d,nv+10 }); } d=nd-1; if(d==0)d=4; if(!vis[nx][ny][d]) { vis[nx][ny][d]=1; Q.push((he) { nx,ny,d,nv+10 }); } } return -1; } void play() { if(ai[1][1]==1||ai[1][1]==2) { printf("-1\n"); return; } int MAX=-1; for(int i=1; i<=4; i++) { int ng=BFS1(i); if(ng==-1) { printf("-1\n"); return; } int nb=BFS2(ex,ey,i); MAX=max(MAX,1000-20-nb-ng); } printf("%d\n",MAX); } int main() { scanf("%d",&T); while(T--) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 3888 Twelves Monkeys
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3888
题意:给你n年,其中有m中关系,Xi Yi,代表从第Xi年可以回到Yi年,其中 Xi>=Yi,然后给你Q个查询,每个查询一个年份q,问你从第q年,至少有两种方案可以回到q年之前的年份有多少年。然后后面就是给你解释,第q年可以等到q年之后然后在回到q年之前。或则直接走,但是m种关系在一条路径中只能用一次。
分析:假设当前查询的是q年,那么我们要知道我们能回到q年之前至少有两条路径有多少年,我们可以从q~n之间的最小Yi和次小Yi。为什么,因为q可以等到q~n之间的一年然后回到最小Yi,或则q可以等到q~n之间的一年然后回到次小Yi,这样就有两条路径可以回到Yi到q之间的年份,且因为次小Yi是第二小的,所以剩下的都大于次小Yi,所以次小Yi是最优的。那么就可以从后往前推,每次更新次小Yi。然后查询的话,如果次小Yi大于等于q,那么就是0,因为回不去,如果小于q,那么就可以会q-次小Yi年,这样的话就Ok了,最后啪啪啪就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=5*12345; struct he { int x,y; } Sky[maxn]; int n,m,q; bool cmp(he a,he b) { return a.x>b.x; } void init() { for(int i=1; i<=m; i++)scanf("%d%d",&Sky[i].x,&Sky[i].y); sort(Sky+1,Sky+1+m,cmp); } int ai[maxn]; void play() { memset(ai,0,sizeof(ai)); int l1=-1,l2=-1; for(int i=1; i<=m; i++) { int now=Sky[i].x; int next=Sky[i].y; if(l1==-1)l1=next; else if(l2==-1) { if(l1>next) { l2=l1; l1=next; } else { l2=next; } } else { if(next<l1) { l2=l1; l1=next; } else if(next<l2) { l2=next; } } ai[now]=l2; } for(int i=n; i>=1; i--) { if(ai[i]==-1)continue; if(ai[i]==0) { ai[i]=ai[i+1]; } } int t; while(q--) { scanf("%d",&t); if(ai[t]==-1||ai[t]==0)printf("0\n"); else { if(ai[t]>=t)printf("0\n"); else printf("%d\n",t-ai[t]); } } } int main() { while(scanf("%d%d%d",&n,&m,&q)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
ZOJ Problem Set - 3885 The Exchange of Items
飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3885
题意:给你n对数据Ai,Bi,Ai代表没有当前值,Bi代表目标值,然后有m个交换,Xi,Yi,说名Xi可以变为Yi,或则Yi可以变为Xi,求最小的交换次数,使得n个数据到达目标值。
分析:一看就知道,假设p为Ai-Bi,如果p大于0,那么i这个点必须要交换掉p个数,如果p<0那么就说明i必须要得到p个数,这样的话,如果我们想知道有可行的方案使得在改变后Ai全都变为Bi,我们可以使用最大流,但是这里我们将p>o加到s1里去,p<0加到s2里去,比较s1和s2是否相等,因为不等的话就肯定跑不了。如果相同,具体怎么建图?p大于0,那么就从超级源点加一条流量为p的边到i,如果小于0,那么就从i加一条流量为p的边到超级汇点,然后根据m个可以交换的边,加m条从Xi到Yi的边,和Yi到Xi的边,因为是双向的,且容量为INF,因为没有限制。这样设最大流max_flow,如果max_flow和s1相等,那么就是可行的。关键题目让我们求最少的交换次数,具体的交换次数就是经过Xi和Yi这条边多少次。那么想到这,应该就知道了,可以用最小费用最大流,p大于0,那么就从超级源点加一条流量为p的边到i且花费为0,如果小于0,那么就从i加一条流量为p的边到超级汇点,花费也为0,具体就是m条边的花费,因为经过一次就要加一次交换次数,那么就是流量为INF,花费为1,这样跑一边,如果max_flow和s1相等,那么输出最小花费就是答案,最后啪啪啪就可以AC了
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <algorithm> using namespace std; #define forr(i,f_start,f_end) for(int i=f_start;i<f_end;++i) #define mem(x,i) memset(x,i,sizeof(x)) const int maxn = 123; const int maxm = 123 * 8; typedef long long LL; const int INF = 0xfffffff; int input() { int a; scanf("%d", &a); return a; } int Flow; ///-----------------最小费用流----------------- //cost 代表一个流量要的费用 cap代表容量 //init 到N+2,如果超级汇点就是0,N+1 //else 就是s到t init到多少个点加1 struct Edge { int to, next, cap, flow, cost; } edge[maxm]; struct MCMF { int head[maxn], tol; int pre[maxn], dis[maxn]; bool vis[maxn]; int N; void init(int n) { N = n; tol = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s, int t) { queue<int>q; for (int i = 0; i<N; i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } if (pre[t] == -1) return false; else return true; } //返回的是最大流,cost存的是最小费用 int minCostMaxflow(int s, int t, int &cost) { int flow = 0; cost = 0; while (spfa(s, t)) { int Min = INF; for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { if (Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; } for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) { edge[i].flow += Min; edge[i ^ 1].flow -= Min; cost += edge[i].cost*Min; } flow += Min; } return flow; } } mcmf; ///----------------------------------------- int N, M; int main() { while (scanf("%d%d", &N, &M)!=EOF) { mcmf.init(N+2); int cmp=0; int cmp1=0; for(int i=1; i<=N; i++) { int a,b; scanf("%d%d",&a,&b); int p=a-b; if(p>0) { cmp+=p; mcmf.addedge(0,i,p,0); } else if(p<0) { cmp1-=p; mcmf.addedge(i,N+1,-p,0); } } int a,b; for(int i=1; i<=M; i++) { scanf("%d%d",&a,&b); mcmf.addedge(a,b,INF,1); mcmf.addedge(b,a,INF,1); } int cost; int Flow = mcmf.minCostMaxflow(0, N+1, cost); if(cmp1!=cmp||cmp!=Flow)printf("-1\n"); else printf("%d\n",cost); } return 0; }