丘比特的烦恼

link

题目不难但是有坑点,详见我发的那个“警示后人”。

就是跑二分图最大匹配,对价值取反之后就变成了最小费用最大流的板子了,注意读题直接跑费用流即可。然而我这个蒟蒻还很是调了一会。

#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;
}
posted @ 2022-07-14 15:50  Feyn618  阅读(21)  评论(0编辑  收藏  举报