Assignment
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1068 Accepted Submission(s): 551
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.
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.
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
Recommend
题意:n个公司m个任务,每个公司只接受一个任务,每个任务只被一个公司接受,每个公司i接受任务j的做事效率为g[i][j],现在已经分配好了,问怎样改变任务分配可以让效率最大,求出要改动的公司数目和增加的效率。
思路:与hdu3315相似,hdu 3315;若点数为N,则把每条边的权值扩大x倍(x>N),若是原有匹配,则再把权值加1。最后KM算法求出ans,则最大权值之和=ans/x,没有被改动的=ans%x。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b) for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b) for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define sf(n) scanf("%d", &n)
#define sff(a,b) scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf printf
#define DBG pf("Hi\n")
typedef long long ll;
using namespace std;
/*
KM算法 O(nx*nx*ny)
求最大权匹配(最佳匹配)
若求最小权匹配,可将权值取相反数,结果取相反数
点的标号从0开始
*/
const int N=110;
int nx,ny; //两边的点数
int g[N][N]; //二分图描述,g赋初值为-INF
int linker[N],lx[N],ly[N]; //y 中各点匹配状态,x,y中的点的标号
int slack[N];
bool visx[N],visy[N];
bool flag;
bool DFS(int x)
{
visx[x]=true;
for (int y=0;y<ny;y++)
{
if (visy[y]) continue;
int tmp=lx[x]+ly[y]-g[x][y];
if (tmp==0)
{
visy[y]=true;
if (linker[y]==-1||DFS(linker[y]))
{
linker[y]=x;
return true;
}
}
else if (slack[y]>tmp)
slack[y]=tmp;
}
return false;
}
int KM()
{
flag=true;
memset(linker,-1,sizeof(linker));
memset(ly,0,sizeof(ly));
for (int i=0;i<nx;i++) //赋初值,lx置为最大值
{
lx[i]=-INF;
for (int j=0;j<ny;j++)
{
if (g[i][j]>lx[i])
lx[i]=g[i][j];
}
}
for (int x=0;x<nx;x++)
{
for (int i=0;i<ny;i++)
slack[i]=INF;
while (true)
{
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
if (DFS(x)) break;
int d=INF;
for (int i=0;i<ny;i++)
if (!visy[i]&&d>slack[i])
d=slack[i];
for (int i=0;i<nx;i++)
if (visx[i])
lx[i]-=d;
for (int i=0;i<ny;i++)
{
if (visy[i])
ly[i]+=d;
else
slack[i]-=d;
}
}
}
int res=0;
for (int i=0;i<ny;i++)
{
if (linker[i]==-1||g[linker[i]][i]<=-INF) //有的点不能匹配的话return-1
{
flag=false;
continue;
}
res+=g[linker[i]][i];
}
return res;
}
//记得nx和ny初始化!!!!!!!!
int n,m;
int main()
{
#ifndef ONLINE_JUDGE
freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin);
#endif
int i,j,x;
while (~sff(n,m))
{
nx=n;
ny=m;
int sum=0;
for (i=0;i<n;i++)
for (j=0;j<m;j++)
{
sf(x);
g[i][j]=x*100;
}
for (i=0;i<n;i++)
{
sf(x);x--;
sum+=g[i][x];
g[i][x]++;
}
int ans=KM();
printf("%d %d\n",n-ans%100,ans/100-sum/100);
}
return 0;
}
/*
3 3
2 1 3
3 2 4
1 26 2
2 1 3
2 3
1 2 3
1 2 3
1 2
*/