CodeForces - 1426E Rock, Paper, Scissors(最小费用最大流+最大费用最大流)

题目链接:点击查看

题目大意:A 和 B 在玩石头剪刀布,A 会出 a1 次石头,a2 次剪刀,a3 次布,同理 B 会出 b1 次石头,b2 次剪刀,b3 次布,若对战顺序是可以进行决定的,问 A 最少能赢多少次,最多能赢多少次

题目分析:一道需要分类讨论非常复杂的贪心题,这里提供一种费用流无脑暴力的方法:

  1. st -> A 的三种决策,流量分别为 a1 , a2 , a3 ,花费为 0
  2. A 的石头 ->
    1. B 的剪刀:流量为 inf ,花费为 1
    2. B 的石头:流量为 inf ,花费为 0
    3. B 的布:流量为 inf , 花费为 0
  3. A 的剪刀 ->
    1. B 的剪刀:流量为 inf ,花费为 0
    2. B 的石头:流量为 inf ,花费为 0
    3. B 的布:流量为 inf , 花费为 1
  4. A 的布 ->
    1. B 的剪刀:流量为 inf ,花费为 0
    2. B 的石头:流量为 inf ,花费为 1
    3. B 的布:流量为 inf , 花费为 0
  5. B 的三种决策 -> ed,流量分别为 b1 , b2 , b3 ,花费为 0

答案对应的就是最小费用最大流和最大费用最大流了

代码:
 

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map> 
using namespace std;
      
typedef long long LL;
      
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;

const int N=1e5+100;//��
 
const int M=1e5+100;//��

int a1,a2,a3,b1,b2,b3;

int st=N-1,ed=st-1,n;
 
struct Edge
{
	int to,w,cost,next;
}edge[M];
 
int head[N],cnt;
 
void addedge(int u,int v,int w,int cost)
{
	edge[cnt].to=v;
	edge[cnt].w=w;
	edge[cnt].cost=cost;
	edge[cnt].next=head[u];
	head[u]=cnt++;
	edge[cnt].to=u;
	edge[cnt].w=0;
	edge[cnt].cost=-cost;
	edge[cnt].next=head[v];
	head[v]=cnt++;
}
 
int d[N],incf[N],pre[N];
 
bool vis[N];
 
bool spfa1(int s,int t)
{
	memset(d,inf,sizeof(d));
	memset(vis,false,sizeof(vis));
    memset(pre,-1,sizeof(pre));
	queue<int>q;
	q.push(s);
	vis[s]=true;
	incf[s]=inf;
	d[s]=0;
	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;
			int w=edge[i].w;
			int cost=edge[i].cost;
			if(!w)
				continue;
			if(d[v]>d[u]+cost)
			{
				d[v]=d[u]+cost;
				pre[v]=i;
				incf[v]=min(incf[u],w);
				if(!vis[v])
				{
					vis[v]=true;
					q.push(v);
				}
			}
		}
	}
	return pre[t]!=-1;
}
 
int update1(int s,int t)
{
	int x=t;
	while(x!=s)
	{
		int i=pre[x];
		edge[i].w-=incf[t];
		edge[i^1].w+=incf[t];
		x=edge[i^1].to;
	}
	return d[t]*incf[t];
}
 
void init()
{
	memset(head,-1,sizeof(head));
	cnt=0;
}
 
int solve1(int st,int ed)
{
	int ans=0;
	while(spfa1(st,ed))
		ans+=update1(st,ed);
	return ans;
}

bool spfa(int s,int t)
{
	memset(d,0xcf,sizeof(d));
	memset(vis,false,sizeof(vis));
    memset(pre,-1,sizeof(pre));
	queue<int>q;
	q.push(s);
	vis[s]=true;
	incf[s]=inf;
	d[s]=0;
	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;
			int w=edge[i].w;
			int cost=edge[i].cost;
			if(!w)
				continue;
			if(d[v]<d[u]+cost)
			{
				d[v]=d[u]+cost;
				pre[v]=i;
				incf[v]=min(incf[u],w);
				if(!vis[v])
				{
					vis[v]=true;
					q.push(v);
				}
			}
		}
	}
	return pre[t]!=-1;
}
 
int update(int s,int t)
{
	int x=t;
	while(x!=s)
	{
		int i=pre[x];
		edge[i].w-=incf[t];
		edge[i^1].w+=incf[t];
		x=edge[i^1].to;
	}
	return d[t]*incf[t];
}
 
int solve(int st,int ed)
{
	int ans=0;
	while(spfa(st,ed))
		ans+=update(st,ed);
	return ans;
}

void build()
{
	init();
	addedge(st,1,a1,0);
	addedge(st,2,a2,0);
	addedge(st,3,a3,0);

	addedge(4,ed,b1,0);
	addedge(5,ed,b2,0);
	addedge(6,ed,b3,0);
	
	addedge(1,4,inf,0);
	addedge(1,5,inf,1);
	addedge(1,6,inf,0);
	
	addedge(2,4,inf,0);
	addedge(2,5,inf,0);
	addedge(2,6,inf,1);

	addedge(3,4,inf,1);
	addedge(3,5,inf,0);
	addedge(3,6,inf,0);
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	cin>>n>>a1>>a2>>a3>>b1>>b2>>b3;
	build();
	printf("%d",solve1(st,ed));
	build();
	printf(" %d",solve(st,ed));

	






   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/108859592