hdu 2853 Assignment KM算法

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853

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.
 
题目描述:n个组和m个任务,Eij表示第i个组完成第j个任务的效率,每个组只能完成一个任务,每个任务只能由一个组完成,目前已经有了一个计划,但是现在我们想要让总效率达到最大,并且在此前提下还需要改变重新分配任务的组的个数最少。求出最大效率减去原先计划的效率和重新分配任务的组的个数。
 
算法分析:这道题的思维方式的确很独特,也很巧妙。首先解决第一个问题:最大效率减去原先计划的效率的差值。最大效率很好解决,用KM算法即可,原先计划的效率直接根据输入统计即可。那么第二个问题呢?重新分配任务的组的最小个数。
方法一:首先为了保证在最大效率情况下尽量选择原先已经分配了的任务,所以我们可以对原先已经分配了的任务在效率上加1,这样即使两个组对同一个任务效率相同也会选择原先的计划,然后我们标记一下有哪些边是原先计划里的。剩下的就是KM了。
说明:这种方法为什么会WA呢,还没有找到原因, 关键在于对每条边权都要乘以一个k(k>n),下面的代码就没有乘以k,想想应该是这种方法下求得的不是最大效率吧,但为什么不是最大效率呢? 每条边都乘以k最后的最大效率再除以k,和直接求得的最大效率不是一样的吗?
若有大牛明白其中奥妙,还望指点一二,在此感谢。
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<algorithm>
  7 #define inf 0x7fffffff
  8 using namespace std;
  9 const int maxn=55;
 10 
 11 int n,m,k,sum;
 12 int lx[maxn],ly[maxn],visx[maxn],visy[maxn];
 13 int link[maxn],slack[maxn],w[maxn][maxn];
 14 int vis[maxn][maxn];
 15 
 16 int dfs(int x)
 17 {
 18     visx[x]=1;
 19     for (int y=1 ;y<=m ;y++)
 20     {
 21         if (visy[y]) continue;
 22         int t=lx[x]+ly[y]-w[x][y];
 23         if (t==0)
 24         {
 25             visy[y]=1;
 26             if (link[y]==-1 || dfs(link[y]))
 27             {
 28                 link[y]=x;
 29                 return 1;
 30             }
 31         }
 32         else if (slack[y]>t) slack[y]=t;
 33     }
 34     return 0;
 35 }
 36 
 37 void KM()
 38 {
 39     memset(link,-1,sizeof(link));
 40     memset(ly,0,sizeof(ly));
 41     for (int i=1 ;i<=n ;i++)
 42     {
 43         lx[i]=-inf;
 44         for (int j=1 ;j<=m ;j++)
 45             lx[i]=max(lx[i],w[i][j]);
 46     }
 47     for (int x=1 ;x<=n ;x++)
 48     {
 49         for (int i=1 ;i<=m ;i++) slack[i]=inf;
 50         while (1)
 51         {
 52             memset(visx,0,sizeof(visx));
 53             memset(visy,0,sizeof(visy));
 54             if (dfs(x)) break;
 55             int d=inf;
 56             for (int i=1 ;i<=m ;i++)
 57             {
 58                 if (!visy[i] && slack[i]<d) d=slack[i];
 59             }
 60             for (int i=1 ;i<=n ;i++)
 61                 if (visx[i]) lx[i] -= d;
 62             for (int i=1 ;i<=m ;i++)
 63             {
 64                 if (visy[i]) ly[i] += d;
 65                 else slack[i] -= d;
 66             }
 67         }
 68     }
 69     int ans=0,cnt=0;
 70     for (int i=1 ;i<=m ;i++)
 71     {
 72         if (link[i]!=-1)
 73         {
 74             ans += w[link[i] ][i];
 75             if (vis[link[i] ][i]) cnt++;
 76         }
 77     }
 78     printf("%d %d\n",n-cnt,ans-sum-cnt);
 79 //    for (int i=1 ;i<=m ;i++)
 80 //    {
 81 //        if (link[i]!=-1) ans += w[link[i] ][i];
 82 //    }
 83 //    printf("%d %d\n",n-ans%k,ans/k-sum);
 84 }
 85 
 86 int main()
 87 {
 88     while (scanf("%d%d",&n,&m)!=EOF)
 89     {
 90         memset(w,0,sizeof(w));
 91         memset(vis,0,sizeof(vis));
 92         k=200;
 93         for (int i=1 ;i<=n ;i++)
 94         {
 95             for (int j=1 ;j<=m ;j++)
 96             {
 97                 scanf("%d",&w[i][j]);
 98                /// w[i][j] *= k;
 99             }
100         }
101         int a;
102         sum=0;
103         for (int i=1 ;i<=n ;i++)
104         {
105             scanf("%d",&a);
106             sum += w[i][a];
107             ///sum += w[i][a]/k;
108             w[i][a] ++ ;
109             vis[i][a]=1;
110         }
111         KM();
112     }
113     return 0;
114 }
View Code

方法二:和方法一的区别就在于对每条边都乘以k(比如k=200),对于原有匹配w[x][y]++,最后的答案最大效率为ans。

那么差值=ans/k-sum;个数=n-ans%k。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<algorithm>
  7 #define inf 0x7fffffff
  8 using namespace std;
  9 const int maxn=55;
 10 
 11 int n,m,k,sum;
 12 int lx[maxn],ly[maxn],visx[maxn],visy[maxn];
 13 int link[maxn],slack[maxn],w[maxn][maxn];
 14 
 15 int dfs(int x)
 16 {
 17     visx[x]=1;
 18     for (int y=1 ;y<=m ;y++)
 19     {
 20         if (visy[y]) continue;
 21         int t=lx[x]+ly[y]-w[x][y];
 22         if (t==0)
 23         {
 24             visy[y]=1;
 25             if (link[y]==-1 || dfs(link[y]))
 26             {
 27                 link[y]=x;
 28                 return 1;
 29             }
 30         }
 31         else if (slack[y]>t) slack[y]=t;
 32     }
 33     return 0;
 34 }
 35 
 36 void KM()
 37 {
 38     memset(link,-1,sizeof(link));
 39     memset(ly,0,sizeof(ly));
 40     for (int i=1 ;i<=n ;i++)
 41     {
 42         lx[i]=-inf;
 43         for (int j=1 ;j<=m ;j++)
 44             lx[i]=max(lx[i],w[i][j]);
 45     }
 46     for (int x=1 ;x<=n ;x++)
 47     {
 48         for (int i=1 ;i<=m ;i++) slack[i]=inf;
 49         while (1)
 50         {
 51             memset(visx,0,sizeof(visx));
 52             memset(visy,0,sizeof(visy));
 53             if (dfs(x)) break;
 54             int d=inf;
 55             for (int i=1 ;i<=m ;i++)
 56             {
 57                 if (!visy[i] && slack[i]<d) d=slack[i];
 58             }
 59             for (int i=1 ;i<=n ;i++)
 60                 if (visx[i]) lx[i] -= d;
 61             for (int i=1 ;i<=m ;i++)
 62             {
 63                 if (visy[i]) ly[i] += d;
 64                 else slack[i] -= d;
 65             }
 66         }
 67     }
 68     int ans=0,cnt=0;
 69     for (int i=1 ;i<=m ;i++)
 70     {
 71         if (link[i]!=-1) ans += w[link[i] ][i];
 72     }
 73     printf("%d %d\n",n-ans%k,ans/k-sum);
 74 }
 75 
 76 int main()
 77 {
 78     while (scanf("%d%d",&n,&m)!=EOF)
 79     {
 80         memset(w,0,sizeof(w));
 81         k=200;
 82         for (int i=1 ;i<=n ;i++)
 83         {
 84             for (int j=1 ;j<=m ;j++)
 85             {
 86                 scanf("%d",&w[i][j]);
 87                 w[i][j] *= k;
 88             }
 89         }
 90         int a;
 91         sum=0;
 92         for (int i=1 ;i<=n ;i++)
 93         {
 94             scanf("%d",&a);
 95             sum += w[i][a]/k;
 96             w[i][a] ++ ;
 97         }
 98         KM();
 99     }
100     return 0;
101 }

 

转载于:https://www.cnblogs.com/huangxf/p/4339786.html

数据治理是确保数据准确性、可靠性、安全性、可用性和完整性的体系和框架。它定义了组织内部如何使用、存储、保护和共享数据的规则和流程。数据治理的重要性随着数字化转型的加速而日益凸显,它能够提高决策效率、增强业务竞争力、降低风险,并促进业务创新。有效的数据治理体系可以确保数据在采集、存储、处理、共享和保护等环节的合规性和有效性。 数据质量管理是数据治理中的关键环节,它涉及数据质量评估、数据清洗、标准化和监控。高质量的数据能够提升业务决策的准确性,优化业务流程,并挖掘潜在的商业价值。随着大数据和人工智能技术的发展,数据质量管理在确保数据准确性和可靠性方面的作用愈发重要。企业需要建立完善的数据质量管理和校验机制,并通过数据清洗和标准化提高数据质量。 数据安全与隐私保护是数据治理中的另一个重要领域。随着数据量的快速增长和互联网技术的迅速发展,数据安全与隐私保护面临前所未有的挑战。企业需要加强数据安全与隐私保护的法律法规和技术手段,采用数据加密、脱敏和备份恢复等技术手段,以及加强培训和教育,提高安全意识和技能水平。 数据流程管理与监控是确保数据质量、提高数据利用率、保护数据安全的重要环节。有效的数据流程管理可以确保数据流程的合规性和高效性,而实时监控则有助于及时发现并解决潜在问题。企业需要设计合理的数据流程架构,制定详细的数据管理流程规范,并运用数据审计和可视化技术手段进行监控。 数据资产管理是将数据视为组织的重要资产,通过有效的管理和利用,为组织带来经济价值。数据资产管理涵盖数据的整个生命周期,包括数据的创建、存储、处理、共享、使用和保护。它面临的挑战包括数据量的快速增长、数据类型的多样化和数据更新的迅速性。组织需要建立完善的数据管理体系,提高数据处理和分析能力,以应对这些挑战。同时,数据资产的分类与评估、共享与使用规范也是数据资产管理的重要组成部分,需要制定合理的标准和规范,确保数据共享的安全性和隐私保护,以及建立合理的利益分配和权益保障机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值