给出N个敌人,以及M个己方人物,每个人物都有一个能力值。
敌人有两种状态,一种是攻击状态,一种是防御状态。
我们的每个人物只能发起攻击一次。
对于攻击状态:我们如果有一个人物的能力值大于等于敌人的能力值,那么可以将其杀死并且能够获得差值的价值。
对于防御状态:我们如果有一个人物的能力值大于敌人的能力值,那么可以将其杀死,但是不会获得价值。
如果没有敌人的情况下,我们还有人物没有发起攻击,那么我们可以获得该人物的能力值的价值。
问怎样攻击敌人能够获得最多的价值。
思路:
考虑费用流/KM去做。
问题分成两种情况:
①n<=m,也就是说,我们不会剩下剩余多余的选手,那么建图方式如下:
1.建立源点,连入各个我方人物,流为1,花费为0.
2.建立汇点,将各个敌人连入汇点,流为1,花费为0.
3.如果我方人物能够击败敌方人物(攻击类型),流为1,花费为差值,
那么接下来跑个最大费用流就行。注意当前情况我们要的是可行流,不用跑满流,满流不一定最大费用。
②n>m,也就是说,我们可能剩下多余的选手,那么建图方式如下:
1.建立源点,连入各个我方人物,流为1,花费为0.
2.建立汇点,将各个敌人连入汇点,流为1,花费为0.
3.如果我方人物能够击败敌方人物(攻击类型),流为1,花费为差值,
4.如果我方人物不能够击败敌方人物(攻击类型),流为1,花费为负INF,
5.如果我方人物能够击败敌方人物(防御类型),流为1,0,
6.如果我方人物不能够击败敌方人物(防御类型),流为1,花费为负INF,
7.每个我方人物连入拓展节点(表示直接获得的价值),流为1,花费为每个人物的能力值。
那么我们接下来希望跑出最大费用最大流,因为只有最大流的时候,我们才允许我方人物直接获取价值,所以这里必须要跑满流。
两种情况取最大值即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<map>
#include<iostream>
#include<queue>
using namespace std;
int output,d;
struct node
{
int from;
int to;
int w;
int f;
int num;
int next;
}e[2000000];
int head[150000];
int vis[150000];
int dis[150000];
int pre[150000];
int path[150000];
struct node2
{
char op[150];
int val;
}a[15000];
int n,ss,tt,cont,nn,mm;
void add(int from,int to,int f,int w)
{
e[cont].from=from;
e[cont].to=to;
e[cont].f=f;
e[cont].w=w;
e[cont].num=cont;
e[cont].next=head[from];
head[from]=cont++;
}
int SPFA()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=tt;i++)dis[i]=-0x3f3f3f3f;
dis[ss]=0;
queue<int >s;
s.push(ss);
while(!s.empty())
{
int u=s.front();
s.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
int f=e[i].f;
if(f&&dis[v]<dis[u]+w)
{
dis[v]=dis[u]+w;
pre[v]=u;
path[v]=e[i].num;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
if(d==1)
{
if(dis[tt]>=0)return 1;
else return 0;
}
else
{
if(dis[tt]!=-0x3f3f3f3f)return 1;
else return 0;
}
}
void Slove()
{
d++;
int ans=0;
int maxflow=0;
while(SPFA()==1)
{
int minn=0x3f3f3f3f;
for(int i=tt;i!=ss;i=pre[i])
{
minn=min(minn,e[path[i]].f);
}
for(int i=tt;i!=ss;i=pre[i])
{
e[path[i]].f-=minn;
e[path[i]^1].f+=minn;
}
maxflow+=minn;
ans+=dis[tt]*minn;
}
// printf("---%d\n",ans);
output=max(output,ans);
}
int xx[150000];
int main()
{
while(~scanf("%d%d",&nn,&mm))
{
output=0,d=0;
ss=nn+mm+1;tt=nn+mm+2;
cont=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=nn;i++)
{
scanf("%s%d",a[i].op,&a[i].val);
}
for(int i=1;i<=mm;i++)scanf("%d",&xx[i]);
for(int i=1;i<=mm;i++)add(ss,i,1,0),add(i,ss,0,0);
for(int i=1;i<=nn;i++)add(i+mm,tt,1,0),add(tt,i+mm,0,0);
for(int i=1;i<=mm;i++)
{
int x=xx[i];
for(int j=1;j<=nn;j++)
{
if(a[j].op[0]=='A'&&x>=a[j].val)
{
add(i,j+mm,1,x-a[j].val);
add(j+mm,i,0,-(x-a[j].val));
}
}
}
Slove();
if(nn<mm)
{
ss=mm*2+1;tt=ss+1;
cont=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=mm;i++)add(ss,i,1,0),add(i,ss,0,0);
for(int i=1;i<=nn;i++)add(i+mm,tt,1,0),add(tt,i+mm,0,0);
for(int i=nn+1;i<=mm;i++)add(i+mm,tt,1,0),add(tt,i+mm,0,0);
for(int i=1;i<=mm;i++)
{
int x=xx[i];
for(int j=1;j<=nn;j++)
{
if(a[j].op[0]=='A')
{
if(x>=a[j].val)
{
add(i,j+mm,1,x-a[j].val);
add(j+mm,i,0,-(x-a[j].val));
}
else
{
add(i,j+mm,1,-10000000);
add(j+mm,i,0,10000000);
}
}
else
{
if(x>a[j].val)
{
add(i,j+mm,1,0);
add(j+mm,i,0,0);
}
else
{
add(i,j+mm,1,-10000000);
add(j+mm,i,0,10000000);
}
}
}
for(int j=nn+1;j<=mm;j++)
{
add(i,j+mm,1,xx[i]);
add(j+mm,i,0,-xx[i]);
}
}
Slove();
}
printf("%d\n",output);
}
}