丘比特的烦恼
题目不难但是有坑点,详见我发的那个“警示后人”。
就是跑二分图最大匹配,对价值取反之后就变成了最小费用最大流的板子了,注意读题直接跑费用流即可。然而我这个蒟蒻还很是调了一会。
#include<bits/stdc++.h>
//#define feyn
#define int long long
const int N=50;
const int M=1000010;
const int maxn=1e9;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline int min(int s1,int s2){
return s1<s2?s1:s2;
}
inline int max(int s1,int s2){
return s1<s2?s2:s1;
}
inline void turn(string &w){
for(int i=w.size()-1;i>=0;i--){
if(w[i]<'a'||w[i]>'z')w[i]=w[i]-'A'+'a';
}
}
inline int p(int wh){
return wh*wh;
}
inline bool line(int x1,int y1,int x2,int y2,int x3,int y3){
//printf("line:%lld %lld %lld %lld %lld %lld\n",x1,y1,x2,y2,x3,y3);
return (y2-y1)*(x3-x1)==(y3-y1)*(x2-x1);
}
struct node{
int x,y;
string name;
}a[N],b[N];
int diss,m,aa[N],bb[N],cnt,ss,tt;
int data[N][N];
struct edge{
int t,v1,v2,next;
}e[M];
int head[N<<3],esum=1;
inline void adde(int fr,int to,int v1,int v2){
e[++esum]=(edge){to,v1,v2,head[fr]};head[fr]=esum;
}
inline void add(int fr,int to,int v1,int v2){
//printf("add:%d %d %d %d\n",fr,to,v1,v2);
adde(fr,to,v1,v2);adde(to,fr,0,-v2);
}
queue<int>q;
int dis[N<<3];
bool vis[N<<3],inq[N<<3];
inline bool check(){
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(inq,false,sizeof(inq));
dis[ss]=0;q.push(ss);
while(!q.empty()){
int wh=q.front();q.pop();inq[wh]=false;
//printf("wh=%d\n",wh);
for(int i=head[wh],th;i;i=e[i].next){
if(e[i].v1==0)continue;
int now=dis[wh]+e[i].v2;
if(now>=dis[th=e[i].t])continue;
dis[th]=now;if(inq[th]==false)inq[th]=true,q.push(th);
}
}
return dis[tt]<maxn;
}
int cost;
inline int dinic(int wh,int val){
if(wh==tt)return cost+=val*dis[wh],val;
int used=0;vis[wh]=true;
for(int i=head[wh],th;i;i=e[i].next){
if(e[i].v1==0||vis[th=e[i].t]||dis[th]!=dis[wh]+e[i].v2)continue;
vis[th]=true;int now=dinic(th,min(val,e[i].v1));
if(now)used+=now,val-=now,e[i].v1-=now,e[i^1].v1+=now;
if(val==0)break;
}
return used;
}
signed main(){
#ifdef feyn
freopen("in.txt","r",stdin);
#endif
read(diss);read(m);
ss=++cnt,tt=++cnt;
for(int i=1;i<=m;i++)aa[i]=++cnt,bb[i]=++cnt;
for(int i=1;i<=m;i++){
add(ss,aa[i],1,0);add(bb[i],tt,1,0);
for(int j=1;j<=m;j++){
data[i][j]=1;
//if(p(a[i].x-b[j].x)+p(a[i].y-b[j].y)>diss*diss)continue;
//add(aa[i],bb[j],1,-1);
}
}
for(int i=1;i<=m;i++){
read(a[i].x);read(a[i].y);
cin>>a[i].name;turn(a[i].name);
}
for(int i=1;i<=m;i++){
read(b[i].x);read(b[i].y);
cin>>b[i].name;turn(b[i].name);
}
string x,y;int val;
//for(int i=1;i<=m;i++)cout<<a[i].name<<" "<<b[i].name<<endl;
//cin>>x;turn(x);
while(true){
cin>>x;turn(x);if(x=="end")break;
cin>>y;turn(y);read(val);
int s1=0,s2=0;//cout<<"ss:"<<x<<" "<<y<<endl;
for(int i=1;i<=m;i++)if(a[i].name==x||a[i].name==y){s1=i;break;}
for(int i=1;i<=m;i++)if(b[i].name==x||b[i].name==y){s2=i;break;}
//printf("now:%d %d\n",s1,s2);
if(p(a[s1].x-b[s2].x)+p(a[s1].y-b[s2].y)>diss*diss)continue;
bool ok=false;
for(int i=1;i<=m;i++){
if(i==s1)continue;
if(a[i].x<min(a[s1].x,b[s2].x)||a[i].x>max(a[s1].x,b[s2].x))continue;
if(a[i].y<min(a[s1].y,b[s2].y)||a[i].y>max(a[s1].y,b[s2].y))continue;
if(line(a[s1].x,a[s1].y,b[s2].x,b[s2].y,a[i].x,a[i].y)==false)continue;
ok=true;
}
for(int i=1;i<=m;i++){
if(i==s2)continue;
if(b[i].x<min(a[s1].x,b[s2].x)||b[i].x>max(a[s1].x,b[s2].x))continue;
if(b[i].y<min(a[s1].y,b[s2].y)||b[i].y>max(a[s1].y,b[s2].y))continue;
if(line(a[s1].x,a[s1].y,b[s2].x,b[s2].y,b[i].x,b[i].y)==false)continue;
ok=true;
}
if(ok==false)data[s1][s2]=val;//add(aa[s1],bb[s2],1,-val);
}
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
if(p(a[i].x-b[j].x)+p(a[i].y-b[j].y)>diss*diss)continue;
add(aa[i],bb[j],1,-data[i][j]);
}
}
while(check())dinic(ss,maxn);
printf("%lld\n",-cost);
return 0;
}
一如既往,万事胜意