POJ-3686 The Windy's 最小权匹配

  题目链接:http://poj.org/problem?id=3686

  这个题目容易想到拆点,开始我是直接拆点在求的,考虑到直接建图复杂度有点高,然后就在找增广路的同时再加点,因为并不是每个点都会达到50个,这样实际复杂度会好很多。敲完之后,样例过了,然后直接叫,WA!后来看了discuss顿然醒悟,找增光路的时候,之前的状态改变了,那么后面的状态也会改变,那么那样求下去就不一定是最优解!所有要保证所有的匹配之间是互补影响的!假设某个工作坊要处理K个命令,时间分别是t1,t2......tk,那么总共的时间就是k*t1+(k-1)*t2+......+tk。发现没有,如果k表示的是倒数第k个命令,那么总时间变为了:t1+2*t2+......+k*tk。所以我们拆点后再建图的时候,边权值w[i][j]*k,(1<=k<=50),那么直接求最小权匹配就行了。那么我们看下时间复杂度,匹配n个点O(n),每个点至多找n次增广路O(n),邻接矩阵的匈牙利O(n^2),总共就是O(50*50*2500*2500),这是理论的时间复杂度,但实际上远远没有这么可怕,因为很难达到最坏情况,而且顶标的维护使得匈牙利算法效率大大的高,所以一般就算O(n^4)的KM算法也够用了。我的代码POJ跑了47ms,这也出乎了我的意料,总感觉POJ的题目数据很弱啊!!!

 1 //STATUS:G++_AC_47MS_1344KB
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #include<math.h>
 6 #include<iostream>
 7 #include<string>
 8 #include<algorithm>
 9 #include<vector>
10 #include<queue>
11 #include<stack>
12 using namespace std;
13 #define LL long long
14 #define Max(a,b) ((a)>(b)?(a):(b))
15 #define Min(a,b) ((a)<(b)?(a):(b))
16 #define mem(a,b) memset(a,b,sizeof(a))
17 #define lson l,mid,rt<<1
18 #define rson mid+1,r,rt<<1|1
19 const int MAX=55,INF=0x3f3f3f3f;
20 
21 int w[MAX][MAX*MAX],S[MAX],T[MAX*MAX],lx[MAX],ly[MAX*MAX],y[MAX*MAX];
22 int Test,n,m,slack;
23 
24 int dfs(int u)
25 {
26     int v,t;
27     S[u]=1;
28     for(v=0;v<m;v++){
29         t=w[u][v]-lx[u]-ly[v];
30         if(!t){
31             if(!T[v]){
32                 T[v]=1;
33                 if(y[v]==-1 || dfs(y[v])){
34                     y[v]=u;
35                     return 1;
36                 }
37             }
38         }
39         else if(t<slack)slack=t;
40     }
41     return 0;
42 }
43 
44 double KM()
45 {
46     int i,j;
47     double s;
48     mem(ly,0);
49     mem(y,-1);
50     for(i=0;i<n;i++){
51         lx[i]=INF;
52         for(j=0;j<m;j++)
53             if(w[i][j]<lx[i])lx[i]=w[i][j];
54     }
55     for(i=0;i<n;i++){
56         while(1){
57             slack=INF;
58             mem(S,0);mem(T,0);
59             if(dfs(i))break;
60             for(j=0;j<n;j++)if(S[j])lx[j]+=slack;
61             for(j=0;j<m;j++)if(T[j])ly[j]-=slack;
62         }
63     }
64     for(i=s=0;i<m;i++)
65         if(y[i]!=-1)s+=w[y[i]][i];
66     return s;
67 }
68 
69 int main()
70 {
71  //   freopen("in.txt","r",stdin);
72     int i,j,k,t;
73     double ans;
74     scanf("%d",&Test);
75     while(Test--)
76     {
77         scanf("%d%d",&n,&m);
78         for(i=0;i<n;i++)
79             for(j=0;j<m;j++)
80                 scanf("%d",&w[i][j]);
81         for(i=0,t=m;i<t;i++)
82             for(j=2;j<=50;j++,m++)
83                 for(k=0;k<n;k++)
84                     w[k][m]=w[k][i]*j;
85         ans=KM();
86 
87         printf("%.6f\n",ans/n);
88     }
89     return 0;
90 }
posted @ 2012-11-24 22:53  zhsl  阅读(281)  评论(0编辑  收藏  举报