CF190 DIV1 B Ciel and Duel 最大费用流

这场CF竟然挂0了好开心!

这题的费用流解法真是……

分两种情况讨论,一种是Ciel选择中间结束,另一种是全部打完

【我一开始总想把两种情况一起解决QAQ】

第一种情况的话,左边是Ciel,右边是Jiro,源点连左边流量1费用0,右边连汇点流量1费用0,对于Jiro的每一张ATK,如果Ciel的卡>=Jiro的卡则连边,流量1费用C-J,跑最大费用流直到某一次的增广路的费用为负数时结束。

对于第二种情况,首先Ciel的卡数要大于Jiro的卡数,左边是Ciel,右边是Jiro,源点连左边流量1费用0,右边连汇点流量1费用0,对于Jiro的每一张ATK,如果Ciel的卡>=Jiro的卡则连边,流量1费用C-J,对于Jiro的每一张DEF,如果Ciel的卡>Jiro的卡则连边,流量1费用0,然后多拉出一个点EX,左边的点连EX流量1费用为这张卡的strength,EX连汇点流量为Ciel的卡数 - Jiro的卡数,费用为0,跑最大费用流,必须满流这种情况才成立。

输出两种方法的最大值。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<utility>
using namespace std;
#define N 1010
#define M 1000010
#define INF (1<<30)
int n,m,s,t,ans;
int head[N],d[N],pre[N],cnt;
bool vis[N];
struct edge
{
	int v,w,c,next;
}e[M];
void addedge(int u,int v,int w,int c)
{
	e[cnt]=(edge){v,w,c,head[u]}; head[u]=cnt++;
	e[cnt]=(edge){u,0,-c,head[v]}; head[v]=cnt++;
}
int spfa()
{
	queue<int> q;
	memset(pre,-1,sizeof(pre));
	for(int i=0;i<N;++i) d[i]=-INF;
	d[s]=0;
	q.push(s);
	while (! q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i!=-1;i=e[i].next)
		if(e[i].w)
		if(d[e[i].v]<d[u]+e[i].c)
		{
			d[e[i].v]=d[u]+e[i].c;
			pre[e[i].v]=i;
			if(! vis[e[i].v]) q.push(e[i].v),vis[e[i].v]=1;
		}
	}
	return d[t]!=-INF;
}
int flow;
void mcmf1()
{
	ans=flow=0;
	while (spfa())
	{
		int u,mn=INF;
		for(u=t;u!=s;u=e[pre[u]^1].v)
			mn=min(mn,e[pre[u]].w);
		if(d[t]<0) break;
		flow+=mn;
		ans+=mn*d[t];
		for(u=t;u!=s;u=e[pre[u]^1].v)
			e[pre[u]].w-=mn,e[pre[u]^1].w+=mn;
	}
}
void mcmf2()
{
	ans=flow=0;
	while (spfa())
	{
		int u,mn=INF;
		for(u=t;u!=s;u=e[pre[u]^1].v)
			mn=min(mn,e[pre[u]].w);
		flow+=mn;
		ans+=mn*d[t];
		for(u=t;u!=s;u=e[pre[u]^1].v)
			e[pre[u]].w-=mn,e[pre[u]^1].w+=mn;
	}
}
int n1,n2,ans1;
char ss[N][6];
int J[N],C[N];
int main ()
{
freopen("1.in","r",stdin);
	scanf("%d%d",&n1,&n2);
	for(int i=1;i<=n1;++i) scanf("%s %d",ss[i],&J[i]);
	for(int i=1;i<=n2;++i) scanf("%d",&C[i]);
	n=n1+n2;
	s=n+1;
	t=s+1;
	cnt=0;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=n1;++i)
		addedge(n2+i,t,1,0);
	for(int i=1;i<=n2;++i)
	{
		addedge(s,i,1,0);
		for(int j=1;j<=n1;++j)
			if(strcmp(ss[j],"ATK")==0 && C[i]>=J[j]) addedge(i,j+n2,1,C[i]-J[j]);
	}
	mcmf1();
	ans1=ans;
	if(n2<=n1)
	{
		printf("%d\n",ans1);
		return 0;
	}
	cnt=0;
	memset(head,-1,sizeof(head));
	int ex=t+1;
	addedge(ex,t,n2-n1,0);
	for(int i=1;i<=n1;++i)
		addedge(n2+i,t,1,0);
	for(int i=1;i<=n2;++i)
	{
		addedge(s,i,1,0);
		addedge(i,ex,1,C[i]);
		for(int j=1;j<=n1;++j)
		{
			if(strcmp(ss[j],"ATK")==0)
			{
				if(C[i]>=J[j]) addedge(i,j+n2,1,C[i]-J[j]);
			}
			else
			{
				if(C[i]>J[j]) addedge(i,j+n2,1,0);
			}
		}
	}
	mcmf2();
	if(flow==n2) printf("%d\n",max(ans,ans1));
	else printf("%d\n",ans1);
	
	return 0;
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值