您的位置:首页 > 其它

二分图相关 小结

2013-03-31 20:06 127 查看
二分图匹配这一块的一大堆概念各种绕,我被虐爽了。。。

特别是其中各种各样的最大——最小关系,互补关系之间的转化等等。。。各种虐心。。。

先推荐一篇很长的文章,讲得比较详细,把几乎所有的问题都涉及到了。

/content/2617219.html

首先是跟最大匹配有关的问题一大堆:

POJ 3041

给一个n*n的矩阵,上面有k颗小行星,你有一把枪,每次可以打一行或者一列,求最少打几次可以把小行星都蒸发掉(什么乱七八糟的。。。)

把行和列看成点,小行星看成连接所在行与列的边,就成了最小点覆盖,等于最大匹配数。

View Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<bitset>
using namespace std;
#define maxn 510
#define maxm 40010
#define key 12345
#define hash_size (1<<21)
#define inf 0x3f3f3f3f
#define ull unsigned long long

struct node
{
int v,end;
ull hash_v;
node *ne;
}edge[maxm],*head[maxn],hash_e[maxn<<1],*hash_tag[hash_size+1];
int n,m,k,tot,l[maxn],slack[maxn],cnt,lx[maxn],ly[maxn],id[maxn];
bitset <maxn> ux,uy;

void addedge(int x,int y,int z)
{
edge[tot].v=z;
edge[tot].end=y;
edge[tot].ne=head[x];
head[x]=edge+tot++;
}
int hash_add(char *str)
{
ull x=0;
for (int len=0;str[len];len++)
x=x*key+(int)str[len];
int t=x&(hash_size);
for (node *p=hash_tag[t];p;p=p->ne)
if (p->hash_v==x) return p-hash_e;
hash_e[++cnt].hash_v=x;
hash_e[cnt].ne=hash_tag[t];
hash_tag[t]=hash_e+cnt;
return cnt;
}
bool find(int x)
{
ux[x]=1;
for (node *p=head[x];p;p=p->ne)
if (!uy[p->end])
{
int t=lx[x]+ly[p->end]-p->v;
if (t==0)
{
uy[p->end]=1;
if (!l[p->end] || find(l[p->end]))
{
l[p->end]=x;
return 1;
}
}
else if (slack[p->end]>t) slack[p->end]=t;
}
return 0;
}
int km()
{
memset(lx,-0x3f,sizeof(lx));
memset(ly,0,sizeof(ly));
memset(l,0,sizeof(l));
for (int i=1;i<=n;i++)
for (node *p=head[i];p;p=p->ne)
if (p->v>lx[i]) lx[i]=p->v;
for (int i=1;i<=n;i++)
{
memset(slack,0x3f,sizeof(slack));
while (1)
{
ux.reset();
uy.reset();
if (find(i)) break;
int d=inf;
for (int j=n+1;j<=n+m;j++)
if (!uy[j] && d>slack[j])
d=slack[j];
for (int j=1;j<=n;j++) if (ux[j]) lx[j]-=d;
for (int j=n+1;j<=n+m;j++)
{
if (uy[j]) ly[j]+=d;
else slack[j]-=d;
}
}
}
int ans=0;
for (int i=n+1;i<=n+m;i++)
if (l[i]) ans+=(lx[l[i]]+ly[i]);
return ans;
}

int main()
{
while(~scanf("%d%d%d",&n,&m,&k))
{
tot=cnt=0;
int xcnt=0,ycnt=n,xmax=0,ymax=0;
memset(hash_tag,0,sizeof(hash_tag));
memset(head,0,sizeof(head));
for (int i=1;i<=k;i++)
{
char c1[30],c2[30];
int x,t1,t2;
scanf("%s%s%d",c1,c2,&x);
t1=hash_add(c1);
t2=hash_add(c2);
if (t1>xmax) xmax=t1,id[t1]=++xcnt;
if (t2>ymax) ymax=t2,id[t2]=++ycnt;
addedge(id[t1],id[t2],-x);
}
printf("%d\n",-km());
}
}


SGU 206

给出一个n个点,m条边的无向图,每条边有边权。现在要你修改一些边的边权,使得前n-1条边是最小生成树,要求总的修改量最小,输出修改后每条边的边权。

题中有一个隐含的不等式,可以与km联系起来。详细题解与代码戳这里:/article/5533080.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: