二分图相关 小结
2013-03-31 20:06
127 查看
二分图匹配这一块的一大堆概念各种绕,我被虐爽了。。。
特别是其中各种各样的最大——最小关系,互补关系之间的转化等等。。。各种虐心。。。
先推荐一篇很长的文章,讲得比较详细,把几乎所有的问题都涉及到了。
/content/2617219.html
首先是跟最大匹配有关的问题一大堆:
POJ 3041
给一个n*n的矩阵,上面有k颗小行星,你有一把枪,每次可以打一行或者一列,求最少打几次可以把小行星都蒸发掉(什么乱七八糟的。。。)
把行和列看成点,小行星看成连接所在行与列的边,就成了最小点覆盖,等于最大匹配数。
View Code
SGU 206
给出一个n个点,m条边的无向图,每条边有边权。现在要你修改一些边的边权,使得前n-1条边是最小生成树,要求总的修改量最小,输出修改后每条边的边权。
题中有一个隐含的不等式,可以与km联系起来。详细题解与代码戳这里:/article/5533080.html
特别是其中各种各样的最大——最小关系,互补关系之间的转化等等。。。各种虐心。。。
先推荐一篇很长的文章,讲得比较详细,把几乎所有的问题都涉及到了。
/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
相关文章推荐
- 二分图相关问题小结
- 开发与OLAP相关小项目的小结
- C语言中获取文件状态的相关函数小结
- 二分图相关题
- Android O CTS 测试之Media相关测试小结(二)
- 线程相关部分知识点小结
- 行人检测(Pedestrian Detection)小结-Part III(相关论文总结报告)
- jackson处理json对象相关小结
- PowerPC PCI-E调试相关资料小结
- 二分图相关总结 8.18
- ECharts相关小结
- 二分图相关-持续更新
- 二分图小结
- 二分图匹配相关所有总结
- 二分图最大匹配相关问题
- 二分图相关定理及其证明(最小点覆盖+最小路径覆盖+最大独立集+最小覆盖集)
- JavaWeb项目相关小结
- Xcode调试相关小结
- Android O CTS 测试之Media相关测试小结(二)
- C++中指针的数据类型和运算相关知识小结