wikioi 丘比特的烦恼 (最大权匹配)
隨著社會的不斷發展,人與人之間的感情越來越功利化。最近,愛神丘比特發現,愛情也已不再是完全純潔的了。這使得丘比特很是苦惱,他越來越難找到合適的男女,并向他們射去丘比特之箭。于是丘比特千里迢迢遠赴中國,找到了掌管東方人愛情的神——月下老人,向他求教。
月下老人告訴丘比特,純潔的愛情并不是不存在,而是他沒有找到。在東方,人們講究的是緣分。月下老人只要做一男一女兩個泥人,在他們之間連上一條紅線,那么它們所代表的人就會相愛——無論他們身處何地。而丘比特的愛情之箭只能射中兩個距離相當近的人,選擇的范圍自然就小了很多,不能找到真正的有緣人。
丘比特聽了月下老人的解釋,茅塞頓開,回去之后用了人間的最新科技改造了自己的弓箭,使得丘比特之箭的射程大大增加。這樣,射中有緣人的機會也增加了不少。
情人節(Valentine's day)的午夜零時,丘比特開始了自己的工作。他選擇了一組數目相等的男女,感應到他們互相之間的緣分大小,并依此射出了神箭,使他們產生愛意。他希望能選擇最好的方法,使被他選擇的每一個人被射中一次,且每一對被射中的人之間的緣分的和最大。
當然,無論丘比特怎么改造自己的弓箭,總還是存在缺陷的。首先,弓箭的射程盡管增大了,但畢竟還是有限的,不能像月下老人那樣,做到“千里姻緣一線牽”。其次,無論怎么改造,箭的軌跡終歸只能是一條直線,也就是說,如果兩個人之間的連線段上有別人,那么莫不可向他們射出丘比特之箭,否則,按月下老人的話,就是“亂點鴛鴦譜”了。
作為一個凡人,你的任務是運用先進的計算機為丘比特找到最佳的方案。
輸入描述?Input Description
輸入文件第一行為正整數k,表示丘比特之箭的射程,第二行為正整數n(n<30),隨后有2n行,表示丘比特選中的人的信息,其中前n行為男子,后n行為女子。每個人的信息由兩部分組成:他的姓名和他的位置。姓名是長度小于20且僅包含字母的字符串,忽略大小寫的區別,位置是由一對整數表示的坐標,它們之間用空格分隔。格式為x y Name。輸入文件剩下的部分描述了這些人的緣分。每一行的格式為Name1 Name2 p。Name1和Name2為有緣人的姓名,p是他們之間的緣分值(p為小于等于255的正整數)。以一個End作為文件結束標志。每兩個人之間的緣分至多只被描述一次。如果沒有被描述,則說明他們緣分值為1。
輸出描述?Output Description
輸出文件僅一個正整數,表示每一對被射中的人之間的緣分的總和。這個和應當是最大的。
樣例輸入?Sample Input
2
3
0 0 Adam
1 1 Jack
0 2 George
1 0 Victoria
0 1 Susan
1 2 Cathy
Adam Cathy 100
Susan George 20
George Cathy 40
Jack Susan 5
Cathy Jack 30
Victoria Jack 20
Adam Victoria 15
End
這道題其實很裸很簡單的,只是有一個地方,如果兩人的線段之間有點,就不能連邊,我一開始以為只判斷三點共線就行,其實必須在兩點之間。有一個坑爹的就是,忽略大小寫,一開始沒有注意到。
#include <cstring> #include <algorithm> #include <map> #include <iostream> #include <string> #include <cstdio> using std::cout; using std::cin; using std::map; using std::string; struct pos {long i;long x;long y; };const long inf = 0x7fff0000; map<string,pos> folks; pos folks2[70]; long fate[70][70]; long dist;long n; long d; long m[70]; bool v[70]; long l[70];bool km(long x) {v[x] = true;//vxfor (long y=n+1;y<2*n+1;y++){if (!v[y]&&(l[x]+l[y]==fate[x][y]))//vy lx ly{v[y] = true;if (m[y]==-1||km(m[y])){m[y] = x;return true;}}}return false; }int main() {cin >> dist >> n;dist *= dist;for (long i=1;i<2*n+1;i++){long x;long y;string name;pos ptmp;cin >> x >> y >> name ;transform(name.begin(),name.end(),name.begin(),::toupper); //全部轉換為大寫字母ptmp.i = i;ptmp.x = x;ptmp.y = y;folks[name] = ptmp;folks2[i] = ptmp;}for (long i=1;i<n+1;i++){for (long j=n+1;j<2*n+1;j++){long x1 = folks2[i].x;long x2 = folks2[j].x;long y1 = folks2[i].y;long y2 = folks2[j].y;if (((y1-y2)*(y1-y2))+((x1-x2)*(x1-x2))>dist) //不在射程內,{fate[i][j]=-inf;continue;}//fate[i][j]=0fate[i][j]=1;//=fate[j][i]=1;for (long k=1;k<2*n+1;k++) //在射程內,還要判斷兩點間是否有其他點{if (k == i || k == j) continue;long x = folks2[k].x;long y = folks2[k].y;if (((x2-x1)*(y-y1)==(y2-y1)*(x-x1))&&((x2>x&&x>x1||x2<x&&x<x1)||(y2>y&&y>y1||y2<y&&y<y1)))//有其他點,則不行{fate[i][j]=-inf;//fate[j][i]=0;break;}}}}for (long i=1;i<n+1;i++) //初始l[x]值為1 ;for (long j=n+1;j<2*n+1;j++)if (fate[i][j]==1){l[i]=1;continue;}while (1){string name1;string name2;long ff;cin >> name1;transform(name1.begin(),name1.end(),name1.begin(),::toupper);if (name1 == "END") break;cin >> name2 >> ff;transform(name2.begin(),name2.end(),name2.begin(),::toupper);long i1 = folks[name1].i;long i2 = folks[name2].i;if (i1 > i2){long tmp = i1;i1 = i2;i2 = tmp;} //保證,i1是男生,i2是女生if (fate[i1][i2]>0) //兩點能連邊,則賦值fate[i1][i2]=ff;//fate[i2][i1]=ff;if (fate[i1][i2]>l[i1]) //l[x]賦邊的最大值l[i1]=fate[i1][i2];}memset(m,-1,sizeof(m));for (long k=1;k<n+1;k++) //匹配{while (1){memset(v,0,sizeof(v));if (km(k)) break; //如果匹配成功,則跳出繼續d = inf; //不成功,找出d值for (long i=1;i<n+1;i++)if (v[i]) //i點在圖中for (long j=n+1;j<2*n+1;j++)if (!v[j]) //j點不在圖if (l[i]+l[j]-fate[i][j]<d)d = l[i]+l[j]-fate[i][j];for (long i=1;i<n+1;i++) //處理..if (v[i]) l[i]-=d;for (long i=n+1;i<2*n+1;i++)if (v[i]) l[i]+=d;}}long ans = 0;for (long i=n+1;i<2*n+1;i++){ans += fate[m[i]][i];}cout << ans;return 0; }
總結
以上是生活随笔為你收集整理的wikioi 丘比特的烦恼 (最大权匹配)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 毕业生档案、户籍、三方协议等问答
- 下一篇: 【成电860考研】《软件工程》-anki