1. 程式人生 > >丘比特的煩惱

丘比特的煩惱

ref while cnblogs sin 並不是 div 結束 www tdi

丘比特的煩惱https://www.luogu.org/problemnew/show/P1500

題目描述

隨著社會的不斷發展,人與人之間的感情越來越功利化。最近,愛神丘比特發現,愛情也已不再是完全純潔的了。這使得丘比特很是苦惱,他越來越難找到合適的男女,並向他們射去丘比特之箭。於是丘比特千裏迢迢遠赴中國,找到了掌管東方人愛情的神——月下老人,向他求教。
月下老人告訴丘比特,純潔的愛情並不是不存在,而是他沒有找到。在東方,人們講究的是緣分。月下老人只要做一男一女兩個泥人,在他們之間連上一條紅線,那麽它們所代表的人就會相愛——無論他們身處何地。而丘比特的愛情之箭只能射中兩個距離相當近的人,選擇的範圍自然就小了很多,不能找到真正的有緣人。
丘比特聽了月下老人的解釋,茅塞頓開,回去之後用了人間的最新科技改造了自己的弓箭,使得丘比特之箭的射程大大增加。這樣,射中有緣人的機會也增加了不少。
情人節(Valentine‘s day)的午夜零時,丘比特開始了自己的工作。他選擇了一組數目相等的男女,感應到他們互相之間的緣分大小,並依此射出了神箭,使他們產生愛意。他希望能選擇最好的方法,使被他選擇的每一個人被射中一次,且每一對被射中的人之間的緣分的和最大。
當然,無論丘比特怎麽改造自己的弓箭,總還是存在缺陷的。首先,弓箭的射程盡管增大了,但畢竟還是有限的,不能像月下老人那樣,做到“千裏姻緣一線牽”。其次,無論怎麽改造,箭的軌跡終歸只能是一條直線,也就是說,如果兩個人之間的連線段上有別人,那麽莫不可向他們射出丘比特之箭,否則,按月下老人的話,就是“亂點鴛鴦譜”了。
作為一個凡人,你的任務是運用先進的計算機為丘比特找到最佳的方案。

輸入格式:

輸入第一行為正整數k,表示丘比特之箭的射程,第二行為正整數n(n<30),隨後有2n行,表示丘比特選中的人的信息,其中前n行為男子,後n行為女子。每個人的信息由兩部分組成:他的姓名和他的位置。姓名是長度小於20且僅包含字母的字符串,忽略大小寫的區別,位置是由一對整數表示的坐標,它們之間用空格分隔。格式為x y Name。輸入文件剩下的部分描述了這些人的緣分。每一行的格式為Name1 Name2 p。Name1和Name2為有緣人的姓名,p是他們之間的緣分值(p為小於等於255的正整數)。以一個End作為文件結束標誌。每兩個人之間的緣分至多只被描述一次。如果沒有被描述,則說明他們緣分值為1。

輸出格式:

輸出僅一個正整數,表示每一對被射中的人之間的緣分的總和。這個和應當是最大的。


最大費用最大流,先說建圖:
1.源點s(編號為0)連所有男人(編號從1到n)
2.所有女人(編號從n+1到2*n)連匯點t(編號為2*n+1)
3.將能匹配(距離小於射程k,連線段上無人)的男人和女人連接
坑點有幾個:
1.沒有提到則自動連1
2.不區分大小寫
3.有重復的輸入,要取max


#include<queue>
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std; const int N=100; int k,n,len,k1,k2,cnt=1,s,t,Ans; int x[N],y[N],last[N],dist[N],prev[N],idx[N],val[N][N]; bool used[N]; string ch1,ch2; string Name[N]; struct edge{ int to,next,w,f;//w容量,f緣分值 }e[2000]; void insert(int u,int v,int f) { e[++cnt]=(edge){v,last[u],1,f};last[u]=cnt; e[++cnt]=(edge){u,last[v],0,-f};last[v]=cnt; } void Change(string &s)//小寫化所有字符串 { for(int i=0;i<s.length();i++)if(s[i]>=‘A‘&&s[i]<=‘Z‘)s[i]+=32; } double D(int u,int v){return sqrt((x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]));} bool check(int u,int v) { if(D(u,v)>k)return 0; for(int i=1;i<=2*n;i++) { if(i==u||i==v)continue; if(D(u,i)+D(v,i)-D(u,v)<0.00001)return 0; } return 1; } queue<int> Q; bool Spfa() { while(!Q.empty())Q.pop(); for(int i=s;i<=t;i++)dist[i]=-1e9; memset(used,0,sizeof(used)); dist[s]=0; used[s]=1; Q.push(s); while(!Q.empty()) { int now=Q.front();Q.pop(); used[now]=0; for(int i=last[now];i;i=e[i].next) { int v=e[i].to; if(dist[v]<dist[now]+e[i].f&&e[i].w) { dist[v]=dist[now]+e[i].f; prev[v]=now; idx[v]=i; if(!used[v]){used[v]=1;Q.push(v);} } } } if(dist[t]==-1e9)return 0; for(int i=t;i!=s;i=prev[i]){e[idx[i]].w--;e[idx[i]^1].w++;} Ans+=dist[t]; return 1; } int main() { cin>>k>>n; t=2*n+1; for(int i=1;i<=n;i++)insert(s,i,0),insert(i+n,t,0); for(int i=1;i<=2*n;i++){cin>>x[i]>>y[i]>>Name[i];Change(Name[i]);} while(1) { cin>>ch1; if(ch1=="End")break; cin>>ch2; Change(ch1);Change(ch2); for(int i=1;i<=2*n;i++) { if(ch1==Name[i])k1=i; if(ch2==Name[i])k2=i; } cin>>len; if(k1>k2)swap(k1,k2);//保證男人在前 val[k1][k2]=max(val[k1][k1],len); } for(int i=1;i<=n;i++) for(int j=n+1;j<=2*n;j++) if(check(i,j))insert(i,j,val[i][j]==0?1:val[i][j]); while(Spfa());//最大費用最大流 cout<<Ans<<endl; return 0; }

丘比特的煩惱