P3701 主主树(最大流)
S-T很显然,然后寿命作为权 连S-T。
然后那个续命,注意自己不会掉血,所以等价于J的生命加上同阵营的YYY的人数。
然后根据克制关系建权1的边,然后跑最大流与m取最小值。
// Problem: P3701 主主树
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3701
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2022-05-31 09:42:56
// --------by Herio--------
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=2e3+5,M=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = {402653189,805306457,1610612741,998244353};
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
template <typename T> //x=max(x,y) x=min(x,y)
void cmx(T &x,T y){
if(x<y) x=y;
}
template <typename T>
void cmn(T &x,T y){
if(x>y) x=y;
}
struct Dinic{
//Dinic O(n^2m)
int n,m,st,ed;
int id(int x,int y){
return (x-1)*m+y;
}
struct edge{
int to,nt;
ll w;
}e[M];
int h[N],cur[N],cnt,dep[N];
void init(int _st,int _ed){
st=_st,ed=_ed;
cnt=1;mst(h,0);
}
Dinic(int _st=0,int _ed=0){init(_st,_ed);}
void add(int u,int v,ll w){
e[++cnt]={v,h[u],w},h[u]=cnt;
e[++cnt]={u,h[v],0},h[v]=cnt;
}
map<string,int>mp;
int bl[N];
void solve(){
mp["J"]=1;
mp["HK"]=2;
mp["W"]=3;
mp["YYY"]=4;
mp["E"]=5;
cnt = 1,mst(h,0);
scanf("%d%d",&n,&m);
st = 0,ed = n+n+1;
int sum = 0,sum1=0;
rep(i,1,n){
string s;cin>>s;
bl[i] = mp[s];
if(bl[i] == 4) sum++;
}
rep(i,1,n){
string s;cin>>s;
bl[i+n] = mp[s];
if(bl[i+n] == 4) sum1++;
}
rep(i,1,n){
int x;cin>>x;
if(bl[i]==1)
x+=sum;
//printf("(%d,%d,%d)\n",st,i,x);
add(st,i,x);
}
rep(i,1,n){
int x;cin>>x;
if(bl[i+n] == 1) x+=sum1;
//("(%d,%d,%d)\n",i+n,ed,x);
add(i+n,ed,x);
}
//("%d,%d\n",sum,sum1);
rep(i,1,n)
rep(j,1,n){
int ok =0;
if(bl[i]==1 && (bl[j+n]==2 || bl[j+n]==3))
ok = 1;
else if(bl[i]==2 && (bl[j+n]==3 || bl[j+n]==5))
ok = 1;
else if(bl[i]==3 && (bl[j+n]==4 || bl[j+n]==5))
ok = 1;
else if(bl[i]==4 && (bl[j+n]==1 || bl[j+n]==2))
ok = 1;
else if(bl[i]==5 && (bl[j+n]==1 || bl[j+n]==4))
ok = 1;
if(ok)
add(i,j+n,1);//,printf("(%d,%d)\n",i,j+n);
}
printf("%lld\n",min(m+0LL,dinic()));
}
ll dfs(int u,ll c){ //search for augment path
if(u==ed) return c;
ll res=c;
for(int &i=cur[u];i;i=e[i].nt){
int v=e[i].to; ll w=e[i].w;
if(w&&dep[v]==dep[u]+1){
ll now=dfs(v,min(res,w));
if(!now) dep[v]=1;
else e[i].w-=now,e[i^1].w+=now,res-=now;
}
if(!res) return c;
}return c-res;
}
bool bfs(){ //layer the graph
queue<int>q;q.push(st);mst(dep,0),dep[st]=1;
while(!q.empty()){
int u=q.front();q.pop();cur[u]=h[u];
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to;ll w=e[i].w;
if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
}
}return dep[ed];
}
ll dinic(){
ll s=0;
while(bfs()) s+=dfs(st,inf);
return s;
}
}G;
int main(){
G.solve();
return 0;
}