二分图 最大匹配

来源:互联网 发布:思途旅游cms破解版 编辑:程序博客网 时间:2024/05/01 20:04

hdu  1150 Machine Schedule  ZOJ 1364  poj  1325

经典的二分图最大匹配的题

题意就是有k个任务要去完成  现在由两个机器A B去完成

A机器有n个模式  B机器有m个模式

第i个任务由A机器的Ai模式  或者B机器的Bi模式去完成  0<=Ai<n   0<=Bi<m

两个机器的初始模式都为0    现在就是安排机器去完成任务  使得机器重启的次数最少(当机器的模式要转换的时候就需要重启)

个人理解就是找出 最少的模式数去完成所有的任务  

二分图最小覆盖数=最大匹配数


对于第i个任务  都有相应的Ai Bi之间有连线  有n个任务就有n条连线

要从这些点中找出最少的覆盖点  与这些点相连的连线就算被这个点覆盖了  

运用匈牙利算法的dfs()搜索  

#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <string.h>#include <string>#define eps 1e-8#define op operator#define MOD  10009#define MAXN  100100#define FOR(i,a,b)  for(int i=a;i<=b;i++)#define FOV(i,a,b)  for(int i=a;i>=b;i--)#define REP(i,a,b)  for(int i=a;i<b;i++)#define REV(i,a,b)  for(int i=a-1;i>=b;i--)#define MEM(a,x)    memset(a,x,sizeof a)#define ll __int64using namespace std;int map[110][110];int vis[110];int link[110];int n,m,k;int res;bool dfs(int x){    for(int i=0;i<m;i++)        if(map[x][i]&&!vis[i])    {        vis[i]=1;        if(link[i]==-1||dfs(link[i]))        {            link[i]=x;            return 1;        }    }    return 0;}void hungary(){    MEM(link,-1);    for(int i=0;i<n;i++)    {        MEM(vis,0);        if(dfs(i))  res++;    }}int main(){//freopen("ceshi.txt","r",stdin);    while(scanf("%d",&n)!=EOF)    {        if(n==0)  break;        MEM(map,0);        scanf("%d%d",&m,&k);        for(int i=0;i<k;i++)        {            int j,x,y;            scanf("%d%d%d",&j,&x,&y);            if(x>0&&y>0)                map[x][y]=1;        }        res=0;        hungary();        printf("%d\n",res);    }    return 0;}

hnu 12939 Welcome Party

Welcome PartyTime Limit: 10000ms, Special Time Limit:50000ms, Memory Limit:65536KBTotal submit users: 31, Accepted users: 16Problem 12939 : No special judgementProblem description

For many summers, the Agile Crystal Mining company ran an internship program for students. They greatly valued interns' ability to self-organize into teams. So as a get-to-know-you activity during orientation, they asked the interns to form teams such that all members of a given team either have first names beginning with the same letter, or last names beginning with the same letter. To make it interesting, they asked the interns to do this while forming as few teams as possible.

As an example, one year there were six interns: Stephen Cook, Vinton Cerf, Edmund Clarke, Judea Pearl, Shafi Goldwasser, and Silvio Micali. They were able to self-organize into three teams:

Stephen Cook, Vinton Cerf, and Edmund Clarke (whose last names all begin with C)

Shafi Goldwasser and Silvio Micali (whose first names begin with S)

Judea Pearl (not an interesting group, but everyone's first name in this group starts with J)

As a historical note, the company was eventually shut down due to a rather strange (and illegal) hiring practice---they refused to hire any interns whose last names began with the letter S, T, U, V, W, X, Y, or Z. (First names were not subject to such a whim, which was fortunate for our friend Vinton Cerf.)

Input

Each year's group of interns is considered as a separate trial. A trial begins with a line containing a single integer N, such that 1 ≤ N ≤ 300, designating the number of interns that year. Following that are N lines---one for each intern---with a line having a first and last name separated by one space. Names will not have any punctuation, and both the first name and last name will begin with an uppercase letter. In the case of last names, that letter will have an additional constraint that it be in the range from 'A' to 'R' inclusive. The end of the input is designated by a line containing the value 0. There will be at most 20 trials.

Output

For each trial, output a single integer, k, designating the minimum number of teams that were necessary.

Sample Input
6Stephen CookVinton CerfEdmund ClarkeJudea PearlShafi GoldwasserSilvio Micali9Richard HammingMarvin MinskeyJohn McCarthyEdsger DijkstraDonald KnuthMichael RabinJohn BackusRobert FloydTony Hoare0
Sample Output
36

给出n个人的名字

根据每个人first name last name的首字母将这些人分组  first name首字母相同的或者last name的首字母相同的就可以分到一个组  求分出最少的组的个数

这题跟上面那题差不多  

#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <string.h>#include <string>#define eps 1e-8#define op operator#define MOD  10009#define MAXN  100100#define FOR(i,a,b)  for(int i=a;i<=b;i++)#define FOV(i,a,b)  for(int i=a;i>=b;i--)#define REP(i,a,b)  for(int i=a;i<b;i++)#define REV(i,a,b)  for(int i=a-1;i>=b;i--)#define MEM(a,x)    memset(a,x,sizeof a)#define ll __int64using namespace std;int map[30][30];int vis[30];int link[30];int m1[30],m2[30];char ch1[110],ch2[110];int res;bool dfs(int x){    for(int i=0;i<26;i++)    {        if(m2[i]==0)  continue;        if(map[x][i]&&!vis[i])        {            vis[i]=1;            if(link[i]==-1||dfs(link[i]))            {                link[i]=x;                return 1;            }        }    }    return 0;}void hungary(){    MEM(link,-1);    for(int i=0;i<26;i++)    {        if(m1[i]==0)  continue;        MEM(vis,0);        if(dfs(i))  res++;    }}int main(){//freopen("ceshi.txt","r",stdin);    int n;    while(scanf("%d\n",&n)!=EOF)    {        if(n==0)  break;        MEM(map,0); MEM(m1,0); MEM(m2,0);        for(int i=0;i<n;i++)        {            scanf("%s",ch1);            scanf("%s",ch2);            int x=ch1[0]-'A';            int y=ch2[0]-'A';            if(!m1[x])  m1[x]=1;            if(!m2[y])  m2[y]=1;            map[x][y]=1;        }        res=0;        hungary();        printf("%d\n",res);    }    return 0;}


UVA 11419SAM I AM
SAM I AM
Input:
Standard Input

Output: Standard Output

 

The world is in great danger!! Mental's forces have returned to Earth to eradicate humankind. Our last hope to stop this great evil isSam “Serious” Stone. Equipped with various powerful weapons, Serious Sam starts his mission to destroy the forces of evil.

After fighting two days and three nights, Sam is now in front of the temple KOPTOS where Mental's general Ugh Zan III is waiting for him. But this time, he has a serious problem. He is in shortage of ammo and a lot of enemies crawling inside the temple waiting for him. After rounding the temple Sam finds that the temple is in rectangle shape and he has the locations of all enemies in the temple.

C:\Documents and Settings\Angel of Death\Desktop\sam grid.gifAll of a sudden he realizes that he can kill the enemies without entering the temple using the great cannon ball which spits out a gigantic ball bigger than him killing anything it runs into and keeps on rolling until it finally explodes. But the cannonball can only shoot horizontally or vertically and all the enemies along the path of that cannon ball will be killed.

Now he wants to save as many cannon balls as possible for fighting with Mental. So, he wants to know the minimum number of cannon balls and the positions from which he can shoot the cannonballs to eliminate all enemies from outside that temple.

 

Input

Here, the temple is defined as a RXC grid. The first line of each test case contains 3 integers:  R(0<R<1001), C(0<C<1001) representing the grid of temple (R means number of row and C means number of column of the grid) and the number of enemies N(0<N<1000001) inside the temple. After that there are N lines each of which contains 2 integers representing the position of the enemies in that temple. Each test case is followed by a new line (except the last one). Input is terminated when R=C=N=0. The size of the input file is around 1.3 MB.

 

Output

For each test case there will be one line output. First print the minimum number (m) of cannonballs needed to wipe out the enemies followed by a single space and thenm positions from which he can shoot those cannonballs. For shooting horizontally print “r” followed by the row number and for vertical shooting print “c” followed by the column number. If there is more than one solution any one will do.

 

Sample Input                               Output for Sample Input

4 4 3

1 1

1 4

3 2

 

4 4 2

1 1

2 2

 

0 00

 

2 r1 r3

2 r1 r2

 


 

题意就是一个图中若干点上有石头  现在需要去清理石头       每次都可以把头一行或者同一列的石头清理掉

现在就是求最少的清理次数可以把图中的石头都清理掉

还要输出清理石头的位置

分别以行和列建图  求最小点覆盖 就是求最大匹配数

若点(x,y)有东西 就对此建边  求最大匹配数其实很好理解 主要是要输出最后匹配的位置有点问题

X中所有未盖点出发扩展匈牙利树,标记树中所有点,那么X中无标记点和Y中有标记点即为答案。匈牙利树就是书上的所有路径都是匹配边与非匹配边间隔。

代码如下:

#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <string.h>#include <string>#define eps 1e-8#define op operator#define MOD  10009#define MAXN  1010#define INF 0x7fffffff#define FOR(i,a,b)  for(int i=a;i<=b;i++)#define FOV(i,a,b)  for(int i=a;i>=b;i--)#define REP(i,a,b)  for(int i=a;i<b;i++)#define REV(i,a,b)  for(int i=a-1;i>=b;i--)#define MEM(a,x)    memset(a,x,sizeof a)#define ll __int64using namespace std;int mp[MAXN][MAXN],row[MAXN],col[MAXN];int vis[MAXN],link[MAXN],tlink[MAXN];int lvis[MAXN],cvis[MAXN];int l,w,n;int res;bool dfs(int x){    for(int i=0;i<w;i++)    {        if(mp[x][i]&&!vis[i])        {            vis[i]=1;            if(link[i]==-1||dfs(link[i]))            {                link[i]=x;                tlink[x]=i;                return 1;            }        }    }    return 0;}void hungary(){    MEM(link,-1);    MEM(tlink,-1);    for(int i=0;i<l;i++)    {        MEM(vis,0);        if(dfs(i))  res++;    }}bool htree(int x){    lvis[x]=1;    for(int i=0;i<w;i++)    {        if(mp[x][i]&&!cvis[i])        {            cvis[i]=1;            if(link[i]==-1||htree(link[i]))                return 1;        }    }    return 0;}int main(){//freopen("ceshi.txt","r",stdin);    while(scanf("%d%d%d",&l,&w,&n)!=EOF)    {        if(l==0&&w==0&&n==0)  break;        MEM(row,0);        MEM(col,0);        MEM(mp,0);        MEM(lvis,0);        MEM(cvis,0);        for(int i=0;i<n;i++)        {            int x,y;            scanf("%d%d",&x,&y);            x--; y--;            mp[x][y]=1;            row[x]=1;            col[y]=1;        }        res=0;        hungary();        printf("%d",res);        for(int i=0;i<l;i++)            if(tlink[i]==-1)   htree(i);        for(int i=0;i<l;i++)            if(!lvis[i]&&row[i])            printf(" r%d",i+1);        for(int i=0;i<w;i++)            if(cvis[i]&&col[i])            printf(" c%d",i+1);        puts("");    }    return 0;}


 




0 0