版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82689197
链接
https://www.luogu.org/problemnew/show/P3701
大意
定义一些攻击规则,问 方手下的人总共能赢得几场比赛?
思路
真的是伪模板。。。
可以观察发现,这道题是一道典型的最大匹配题
把一点血量当作一个人,续命理解为新增一个人,那么这样就形成了下面这张图
但如果我们每个点每种血量都专门建入点和出点,因为生命最多为五十,这样子的时间复杂度为
是不能接受的
考虑到这些容量为1的点是可以组合在一起的,所有就有了下面这张图
这样子的时间复杂度就被压缩成了
代码
#include<queue>
#include<cstdio>
#include<cstring>
#define N 101
#define M 160001
#define r(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;int n,m,tot,l[M],d[M],S,T,ans,ba[N],bs[N],jxa,jxs;
char ra[N][3],rs[N][3];
struct node{int next,to,w;}e[M<<1];
inline int read()//输入优化
{
int f=0;char c;
while(c=getchar(),c<48||c>57);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48;
return f;
}
inline void add(register int u,register int v,register int w)//建边
{
e[tot]=(node){l[u],v,w};l[u]=tot++;
e[tot]=(node){l[v],u,0};l[v]=tot++;
return;
}
inline bool bfs()//bfs建造分层图
{
memset(d,-1,sizeof(d));
queue<int>q;d[S]=0;q.push(S);
while(q.size())
{
int x=q.front();q.pop();
for(int i=l[x];~i;i=e[i].next)
{
int y=e[i].to;
if(e[i].w&&d[y]==-1)
{
d[y]=d[x]+1;
q.push(y);
if(y==T) return true;
}
}
}
return false;
}
inline int dfs(register int x,register int flow)//dfs计算可行流
{
if(x==T||!flow) return flow;
int rest=0,f=0;
for(int i=l[x];~i;i=e[i].next)
{
int y=e[i].to;
if(d[x]+1!=d[y]||!e[i].w)continue;
f=dfs(y,min(flow-rest,e[i].w));
if(!f) {d[y]=-1;continue;}
e[i].w-=f;rest+=f;e[i^1].w+=f;
if(rest==flow) return flow;
}
return rest;
}
inline void dinic(){while(bfs()) ans+=dfs(S,2147483647);return;}//dinic计算最大流
int main()
{
memset(l,-1,sizeof(l));
n=read();m=read();
r(i,1,n) scanf("%s",ra[i]),jxa+=ra[i][0]=='Y'?1:0;getchar();//输入
r(i,1,n) scanf("%s",rs[i]),jxs+=rs[i][0]=='Y'?1:0;getchar();//输入
r(i,1,n) ba[i]=read();
r(i,1,n) bs[i]=read();//输入
S=0;T=n<<1|1;//建立源点和汇点
r(i,1,n)
r(j,1,n)
{
char s1=ra[i][0],s2=rs[j][0];
if(s1=='J'&&(s2=='H'||s2=='W'))
add(i,j+n,1);
if(s1=='E'&&(s2=='J'||s2=='Y'))
add(i,j+n,1);
if(s1=='Y'&&(s2=='J'||s2=='H'))
add(i,j+n,1);
if(s1=='H'&&(s2=='E'||s2=='W'))
add(i,j+n,1);
if(s1=='W'&&(s2=='Y'||s2=='E'))
add(i,j+n,1);//若能击败则连边
}
r(i,1,n)
{
char s1=ra[i][0],s2=rs[i][0];
if(s1=='J') add(S,i,ba[i]+jxa);else add(S,i,ba[i]);
if(s2=='J') add(i+n,T,bs[i]+jxs);else add(i+n,T,bs[i]);//若有加血记得加上加血
}
dinic();
if(m<ans) ans=m;//因为我们可能可以多次击败,但是不能超过m
printf("%d",ans);//输出
}