【HDU 2853】Assignment (KM)

Assignment



Problem Description
Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better.
We have N companies of troops and M missions, M>=N. One company can get only one mission. One mission can be assigned to only one company. If company i takes mission j, we can get efficiency Eij. 
We have a assignment plan already, and now we want to change some companies’ missions to make the total efficiency larger. And also we want to change as less companies as possible.

 

Input
For each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.

 

Output
For each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.

 

Sample Input
3 3 2 1 3 3 2 4 1 26 2 2 1 3 2 3 1 2 3 1 2 3 1 2

 

Sample Output
2 26 1 2

 

Source
 
 
【题意】
  有N个公司,M个任务,(N<=M)每个公司做每个任务都有一个效率值,每个公司开始都安排了一个任务,求调整之后效率值总和最大,并使调整的公司尽量少
 
【分析】
  

  哇塞这题建图好巧妙!!!先要效率和最大,然后调整次数最少,把每条边的权值扩大k倍(k>n),然后属于原始任务的边权值+1,权值加1是为了当两条边权值相同时,更优先选择属于原始任务的边,扩大k倍的巧妙之处不仅在于KM匹配时优先选择原始边所得答案除k得到原始答案,而且结果对k求余就是保留的就是原始任务的数量。
  感觉,如果两边点数不一样,然后求最佳完备匹配的话呢,要把点数小的放左边,然后直接求,根据KM算法的步骤,是会先算到最大的那一个的,因为顶标是不断减小的??

  (其实我也不是很清楚)

 

代码如下:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 110
  9 #define Maxm 3010
 10 #define INF 0xfffffff
 11 
 12 struct node
 13 {
 14     int x,y,c,next;
 15 }t[Maxm];int len;
 16 int first[Maxn];
 17 
 18 void ins(int x,int y,int c)
 19 {
 20     t[++len].x=x;t[len].y=y;t[len].c=c;
 21     t[len].next=first[x];first[x]=len;
 22 }
 23 
 24 int mymin(int x,int y) {return x<y?x:y;}
 25 int mymax(int x,int y) {return x>y?x:y;}
 26 
 27 int w[Maxn][Maxn];
 28 
 29 int lx[Maxn],ly[Maxn];
 30 int slack[Maxn],match[Maxn];
 31 bool visx[Maxn],visy[Maxn];
 32 
 33 int n,m;
 34 
 35 bool ffind(int x)
 36 {
 37     visx[x]=1;
 38     for(int i=first[x];i;i=t[i].next) if(!visy[t[i].y])
 39     {
 40         int y=t[i].y;
 41         if(t[i].c==lx[x]+ly[y])
 42         {
 43             visy[y]=1;
 44             if(!match[y]||ffind(match[y]))
 45             {
 46                 match[y]=x;
 47                 return 1;
 48             }
 49         }
 50         else slack[y]=mymin(slack[y],lx[x]+ly[y]-t[i].c);
 51     }
 52     return 0;
 53 }
 54 
 55 void solve()
 56 {
 57     memset(ly,0,sizeof(ly));
 58     memset(match,0,sizeof(match));
 59     for(int i=1;i<=n;i++)
 60     {
 61         lx[i]=-INF;
 62         for(int j=first[i];j;j=t[j].next)
 63             lx[i]=mymax(lx[i],t[j].c);
 64     }
 65     int i;
 66     for(i=1;i<=n;i++)
 67     {
 68         for(int j=1;j<=m;j++) slack[j]=INF;
 69         while(1)
 70         {
 71             memset(visx,0,sizeof(visx));
 72             memset(visy,0,sizeof(visy));
 73             if(ffind(i)) break;
 74             int delta=INF;
 75             for(int j=1;j<=m;j++) if(!visy[j])
 76                 delta=mymin(delta,slack[j]);
 77             if(delta==INF) return;
 78             for(int j=1;j<=n;j++) if(visx[j]) lx[j]-=delta;
 79             for(int j=1;j<=m;j++) 
 80               if(visy[j]) ly[j]+=delta;
 81               else if(slack[j]!=INF) slack[j]-=delta;
 82         }
 83     }
 84 }
 85 
 86 int main()
 87 {
 88     while(scanf("%d%d",&n,&m)!=EOF)
 89     {
 90         len=0;
 91         memset(first,0,sizeof(first));
 92         for(int i=1;i<=n;i++)
 93          for(int j=1;j<=m;j++)
 94          {
 95              scanf("%d",&w[i][j]);
 96              w[i][j]*=(n+1);
 97          }
 98         int sum=0,ans=0;
 99         for(int i=1;i<=n;i++)
100         {
101             int x;
102             scanf("%d",&x);
103             sum+=w[i][x];
104             w[i][x]++;
105         }
106         for(int i=1;i<=n;i++)
107          for(int j=1;j<=m;j++)
108          {
109             ins(i,j,w[i][j]);
110          }
111         
112         solve();
113         for(int i=1;i<=m;i++) if(match[i]) ans+=lx[match[i]]+ly[i];
114         printf("%d %d\n",n-ans%(n+1),(ans-sum)/(n+1));
115     }
116     return 0;
117 }
[HDU 2853]

 

2016-10-27 13:17:06

posted @ 2016-10-27 13:12  konjak魔芋  阅读(226)  评论(0编辑  收藏  举报