zoukankan      html  css  js  c++  java
  • bzoj1449: [JSOI2009]球队收益&&bzoj2597: [Wc2007]剪刀石头布

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1449

    http://www.lydsy.com/JudgeOnline/problem.php?id=2597

    思路:首先是球队收益,有输有赢不好处理

    先假设后面所有比赛都是输,算出收益

    然后计算未进行的比赛会带来多少收益


    首先从S向每场比赛连边,容量为1,表示比赛只能有一个队赢,费用为0

    每场比赛向比赛的两个队连边,容量为1,费用为0

    关键是怎么计算每个队增加的收益


    拆边,把每多赢一场增加的收益作为费用,容量为1

    现在一个队已经赢了win[i]场,输了lose[i]+rem[i](剩下未比赛的场数)场

    现在它的收益为C[i]*win[i]^2+D[i]*(lose[i]+rem[i])^2

    那么它如果多赢了一场

    收益为C[i]*(win[i]+1)^2+D[i]*(lose[i]+rem[i]-1)^2

    做差可得2*C[i]*win[i]-2*D[i]*(lose[i]+rem[i])+C[i]+D[i]

    这就是它在剩余的比赛中赢第一场的收益


    同样,它在剩余比赛中赢的第j场的收益为

    2*C[i]*(win[i]+j)-2*D[i]*(lose[i]+rem[i]-j)+C[i]+D[i]

    这个是单调增的,也只有单调增时才能拆边

    因为我们这时不会先得到后一场的收益,再得到前一场的收益


    所以从每个队向T连0-rem[i]这rem[i]+1条边

    每条边的费用就是这场比赛能带来的收益


    剪刀石头布就难想一些

    首先是补集转化

    总共有C(n,3)个三元组


    一个三元组中,如果有一个点赢了两场,那么就不是“剪刀石头布

    所以答案就是C(n,3)-ΣC(win[i],2)

    展开:C(n,3)-(win[i])*(win[i]-1)/2

    同样建图,展开,发现后面部分每赢一场能得到的收益为增,这里是求最小费用,所以也一定会按场次顺序选择边流过


    bzoj1449:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=10010,maxm=200010,inf=1061109567;
    using namespace std;
    int n,m,win[maxn],los[maxn],C[maxn],D[maxn],rem[maxn],mincost,maxflow,sum;
    struct data{int x,y;}G[maxn];
    inline int game(int x){return x;}
    inline int team(int x){return m+x;}
    
    struct zkw_flow{
    	int pre[maxm],now[maxn],son[maxm],val[maxm],cost[maxm],tot,dis[maxn],S,T,q[maxn+10],head,tail;bool bo[maxn];
    	void add(int a,int b,int c,int d){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c,cost[tot]=d;}
    	void ins(int a,int b,int c,int d){add(a,b,c,d),add(b,a,0,-d);}
    	void init(){memset(now,0,sizeof(now)),tot=1;}
    	void spfa(){
    		memset(dis,63,sizeof(dis));
    		memset(bo,0,sizeof(bo));
    		q[tail=1]=S,dis[S]=head=0,bo[S]=1;
    		while (head!=tail){
    			if (++head>maxn) head=1;
    			int x=q[head];
    			for (int y=now[x];y;y=pre[y]){
    				if (val[y]>0&&dis[son[y]]>dis[x]+cost[y]){
    					dis[son[y]]=dis[x]+cost[y];
    					if (!bo[son[y]]){
    						if (++tail>maxn) tail=1;
    						q[tail]=son[y],bo[son[y]]=1;
    					}
    				}
    			}
    			bo[x]=0;
    		}
    	}
    	bool relabel(){
    		int mins=inf;
    		for (int i=S;i<=T;i++) if (bo[i])
    			for (int y=now[i];y;y=pre[y]) if (!bo[son[y]]&&val[y])
    				mins=min(mins,dis[i]+cost[y]-dis[son[y]]);
    		if (mins==inf) return 0;
    		for (int i=S;i<=T;i++) if (!bo[i]) dis[i]+=mins;
    		return 1;
    	}
    	int find(int x,int low,int cos){
    		if (x==T){mincost+=low*cos;return low;}
    		bo[x]=1;int res=0;
    		for (int y=now[x];y&&low;y=pre[y]){
    			if (!val[y]||bo[son[y]]||dis[son[y]]!=dis[x]+cost[y]) continue;
    			int tmp=find(son[y],min(low,val[y]),cos+cost[y]);
    			res+=tmp,low-=tmp,val[y]-=tmp,val[y^1]+=tmp;
    		}
    		return res;
    	}
    	void work(){
    		spfa();int aug=0;
    		do{
    			do{
    				memset(bo,0,sizeof(bo));
    				aug=find(S,inf,0),maxflow+=aug;
    			}while (aug);
    		}while (relabel());
    	}
    }F;
    
    int main(){
    	scanf("%d%d",&n,&m),F.S=0,F.T=m+n+1;F.init();
    	for (int i=1;i<=n;i++) scanf("%d%d%d%d",&win[i],&los[i],&C[i],&D[i]);
    	for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),G[i]=(data){x,y},rem[x]++,rem[y]++;
    	for (int i=1;i<=n;i++) sum+=win[i]*win[i]*C[i]+(los[i]+rem[i])*(los[i]+rem[i])*D[i];
    	for (int i=1;i<=m;i++) F.ins(F.S,game(i),1,0),F.ins(game(i),team(G[i].x),1,0),F.ins(game(i),team(G[i].y),1,0);
    	for (int i=1;i<=n;i++)
    		for (int j=0;j<=rem[i];j++)
    			F.ins(team(i),F.T,1,2*(win[i]+j)*C[i]-2*(los[i]+rem[i]-j)*D[i]+C[i]+D[i]);
    	F.work(),printf("%d
    ",sum+mincost);
    	return 0;
    <span style="font-size:14px;">}</span>

    bzoj2597

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=15010,maxm=60010,inf=1061109567;
    using namespace std;
    int n,g[105][105],win[105],sum,maxflow,totcost;
    inline int team(int x){return x+n*n;}
    inline int game(int x,int y){return (x-1)*n+y;}
    
    struct zkw_flow{
    	int pre[maxm],now[maxn],son[maxm],val[maxm],cost[maxm],dis[maxn],tot,S,T;bool bo[maxn];
    	void add(int a,int b,int c,int d){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c,cost[tot]=d;}
    	void ins(int a,int b,int c,int d){add(a,b,c,d),add(b,a,0,-d);}
    	void init(){memset(now,0,sizeof(now)),tot=1;}
    	bool relabel(){
    		int mins=inf;
    		for (int i=S;i<=T;i++) if (bo[i])
    			for (int y=now[i];y;y=pre[y]) if (val[y]&&!bo[son[y]])
    				mins=min(mins,dis[i]+cost[y]-dis[son[y]]);
    		if (mins==inf) return 0;
    		for (int i=S;i<=T;i++) if (!bo[i]) dis[i]+=mins;
    		return 1;
    	}
    	int find(int x,int low,int cos){
    		if (x==T){totcost+=cos*low;return low;}
    		bo[x]=1;int res=0;
    		for (int y=now[x];y;y=pre[y]){
    			if (bo[son[y]]||!val[y]||dis[x]+cost[y]!=dis[son[y]]) continue;
    			int tmp=find(son[y],min(low,val[y]),cos+cost[y]);
    			res+=tmp,low-=tmp,val[y]-=tmp,val[y^1]+=tmp;
    			if (!low) break;
    		}
    		return res;
    	}
    	void work(){
    		int aug=0;memset(dis,0,sizeof(dis)),maxflow=totcost=0;
    		do{
    			do{
    				memset(bo,0,sizeof(bo));
    				aug=find(S,inf,0),maxflow+=aug;
    			}while (aug);
    		}while (relabel());
    	}
    	void print(){
    		for (int i=game(1,1);i<=game(n,n);i++) if (now[i]){
    			int y1=now[i],y2=pre[y1],v1=son[y1]-n*n,v2=son[y2]-n*n;
    			if (!val[y1]) g[v1][v2]=1,g[v2][v1]=0;
    			else g[v2][v1]=1,g[v1][v2]=0;
    		}
    	}
    }F;
    
    int main(){
    	scanf("%d",&n),F.init(),F.S=0,F.T=team(n)+1;
    	for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&g[i][j]),win[i]+=(g[i][j]==1);
    	for (int i=1;i<=n;i++) sum+=win[i]*(win[i]-1)/2;
    	for (int i=1;i<=n;i++) for (int j=win[i];j<=n;j++) F.ins(team(i),F.T,1,j);
    	for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (g[i][j]==2)
    		F.ins(F.S,game(i,j),1,0),F.ins(game(i,j),team(i),1,0),F.ins(game(i,j),team(j),1,0);
    	F.work(),F.print();
    	printf("%d
    ",n*(n-1)*(n-2)/6-sum-totcost);
    	for (int i=1;i<=n;i++,puts("")) for (int j=1;j<=n;j++) printf("%d ",g[i][j]);
    	return 0;
    }




  • 相关阅读:
    为何url地址不是直接发送到服务器,而是被编码后再发送
    http请求分析
    Nginx+Php不支持并发,导致curl请求卡死(Window环境)
    Vue开发调试神器 vue-devtools
    什么是闭包?闭包的优缺点?
    Nginx 504 Gateway Time-out分析及解决方法
    HTTP请求8种方法
    MySQL查询缓存总结
    MySQL单表多次查询和多表联合查询,哪个效率高?
    分布式系统一致性问题解决实战
  • 原文地址:https://www.cnblogs.com/thythy/p/5493457.html
Copyright © 2011-2022 走看看