HDU 2255 奔小康赚大钱 带权二分图匹配 KM算法
奔小康賺大錢
Time Limit: 1000/1000 MS (Java/Others)????Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13984????Accepted Submission(s): 6102
Problem Description
傳說在遙遠的地方有一個非常富裕的村落,有一天,村長決定進行制度改革:重新分配房子。
這可是一件大事,關系到人民的住房問題啊。村里共有n間房間,剛好有n家老百姓,考慮到每家都要有房住(如果有老百姓沒房子住的話,容易引起不安定因素),每家必須分配到一間房子且只能得到一間房子。
另一方面,村長和另外的村領導希望得到最大的效益,這樣村里的機構才會有錢.由于老百姓都比較富裕,他們都能對每一間房子在他們的經濟范圍內出一定的價格,比如有3間房子,一家老百姓可以對第一間出10萬,對第2間出2萬,對第3間出20萬.(當然是在他們的經濟范圍內).現在這個問題就是村領導怎樣分配房子才能使收入最大.(村民即使有錢購買一間房子但不一定能買到,要看村領導分配的).
?Input
輸入數據包含多組測試用例,每組數據的第一行輸入n,表示房子的數量(也是老百姓家的數量),接下來有n行,每行n個數表示第i個村名對第j間房出的價格(n<=300)。
?Output
請對每組數據輸出最大的收入值,每組的輸出占一行。
?
Sample Input
2 100 10 15 23Sample Output
123Source
HDOJ 2008 Summer Exercise(4)- Buffet Dinner
?Recommend
lcy
分析:
KM算法就是在匈牙利算法的基礎上加了權值的束縛,為了達到權值和最大或者最小,就不能簡單的去算邊數
1.首先找到所有居民愿意花錢最多的那個房子,同時調節 lx,ly數組,使得權值和最大,或者當要松弛的時候,使得本來最大的矛盾權值和,盡可能的損失少一些,來得到滿足條件的最大權值和
2.在 lx[x]+ly[y]=w[x][y]條件下進行匈牙利算法,既可以讓居民住他花錢最多的房子,又可以在多居民搶一個房子的時候,用它來得到該居民到其他房子的松弛量(即該居民到其它房子 比 到這個用錢最多的房子 愿意花的錢數上差的值。)
那么我們就要把 發生矛盾的居民到 其它房子的松弛量 ?的最小值求出來。再用它去松弛,就可以讓原本矛盾的最大權值和,損失最小而得到滿足條件的最大權值和!
對于每個居民有4個基本問題:
1.這個房子訪問過沒有?
2.這個房子能不能滿足他的條件
3.這個房子是否被別人住了
4.被別人住了能不能得到調配
//HDU2255 #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 310 #define INF 0x3f3f3f3f #define clr(x) memset(x,0,sizeof(x)) int w[maxn][maxn];//w[i][j]表示i到j的權值 int lx[maxn],ly[maxn];//同時調節兩個數組,使得權值和最大 int n; //n1,n2為二分圖的頂點集,其中x屬于n1,y屬于n2 //link記錄n2中的點y在n1中所匹配的x點的編號 int link[maxn]; int slack[maxn];//松弛操作 int visx[maxn],visy[maxn]; bool dfs(int x) {visx[x]=1;//得到發生矛盾的居民集合//對于這個居民,每個房子都試一下,找到就退出for(int y=1;y<=n;y++){if(visy[y]) continue;//不需要重復訪問int t=lx[x]+ly[y]-w[x][y];//這個條件下使用匈牙利算法if(t==0)//標志這個房子可以給這個居民{visy[y]=1; //這個房子沒人住或者可以讓住著個房子的人去找另外的房子住if(link[y]==0||dfs(link[y])){link[y]=x;return 1;//可以讓這位居民住進來}}else if(slack[y]>t)//否則這個房子不能給這位居民slack[y]=t;}return 0; } int KM() {clr(lx);clr(ly);clr(link);//首先把每個居民出的錢最多的那個房子給他for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(lx[i]<w[i][j])lx[i]=w[i][j];//在滿足上述條件之后,給第i位居民分配房子for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)slack[j]=INF;//松弛量while(1)//直到給這個居民找到房子為止{clr(visx);clr(visy);if(dfs(i)) break;//找到房子,就跳出循環int d=INF;for(int k=1;k<=n;k++)if(!visy[k]&&d>slack[k])d=slack[k];//找到最小松弛量for(int k=1;k<=n;k++)//松弛操作,使發生矛盾的居民有更多選擇{if(visx[k]) lx[k]-=d;//將矛盾居民的要求降低,使發生矛盾的居民有更多if(visy[k]) ly[k]+=d;//使發生矛盾的房子在下一個子圖,保持矛盾}}}int ans=0;for(int i=1;i<=n;i++)ans+=w[link[i]][i];return ans; } int main() {while(~scanf("%d",&n)){clr(w);//每個案例都重置為0for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&w[i][j]);//輸入每條邊的權值printf("%d\n",KM());}return 0; }?
總結
以上是生活随笔為你收集整理的HDU 2255 奔小康赚大钱 带权二分图匹配 KM算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 2063 过山车 二分图匹配 匈
- 下一篇: O(1)快速乘