您的位置:首页 > 其它

2018年3月1日训练日记

2018-03-01 14:05 183 查看
今天看了 一般图匹配的带花树算法。
看了几个大佬的博客,也是有点懵:
寻找增广路的做法是:从一个还没被匹配的点(exposed vertex)出发,中间形成交错路径,最后停止在一个没被匹配的点,这就是一条增广路。
定义:在路径上给这些点从1开始标号,奇数的点我们称为外点,偶数的点我们称为内点,可以发现他们恰好对应两个集合(X为外点的集合,Y为内点的集合)

直接寻找增广路做法不适用于一般图匹配的原因:寻找增广路时会形成环,导致有些点既是内点又是外点。找到增广路时都会把未匹配边变成匹配边,匹配边变成未匹配边,若是有些点既是外点又是内点,会匹配出错,即一个点存在于两个匹配中
注意:一般图中只会出现root连两条未匹配边,因为寻找增广路都是从未匹配点开始的。
带花树的做法是:
像匈牙利算法那样不断枚举点寻找增广路,
当找到环时,找到u和v的最近公共祖先,
分别从u和v跑到最近公共祖先的过程中,把环里面的边从有向变成无向的,并环中点的所在集合都设为root



(以上内容大部分为大佬的博客部分内容)

题目:
Ural-1099 Work scheduling 带花树模板题

ZJU 3316 Game 是否存在完美匹配,如果不是先手就可以走未匹配的点,必赢

HDU 3446 daizhenyang's chess  两次匹配,第一次不带king第二次带。若匹配数增加就说明king开始有一条增广路,必赢。

HDU 4687 Boke and Tsukkomi 先求出最大匹配sum,然后枚举每个匹配,删除这个匹配再求最大匹配,若为sum-1就说明这个匹配不是多余的,否则就是多余的

HDU 3551 hard problem 因为要删边使度数减少,所以先拆边,每条边拆成两个点,连边,然后我们把每个点拆成deg[i]-D[i]个点(deg[i]为原图度数,D[i]为子图度数),然后对所有该点和他的边(i,e)组成的点连一条边,表示这个点缺少的度数,可以由这儿得到。接着,求匹配,如果是完美匹配,即:每个度数都找到了可以使他减少的边。这个子图可以得到。

代码还是比较长的。。。
附个人带花树算法模板(Ural-1099 Work scheduling):#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define maxn 250
#define maxm maxn*maxn*2
#define INF 1e9
using namespace std;
inline int read()
{
register int c=getchar(),fg=1,sum=0;
while(c>'9'||c<'0') {if(c == '-')fg = -1;c=getchar();}
while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
return fg*sum;
}
deque<int>Q;
bool lk[maxn][maxn];
int n,m,k,p,ans,sum,g[maxm],ql,qr,pre[maxn],base[maxn],tim;
bool inq[maxn],inb[maxn],inp[maxn];
struct node{
int u,v;
}e[maxm];
int lca(int x,int y){
memset(inp,0,sizeof(inp));
while(1){
x=base[x];
inp[x]=1;
if(g[x]==-1) break;
x=pre[g[x]];
}
while(1){
y=base[y];
if(inp[y]) return y;
y=pre[g[y]];
}
}
void sk(int x,int p){
while(x!=p)
{
int y=g[x];
inb[base[x]]=1;
inb[base[y]]=1;
y=pre[y];
if(base[y]!=p) pre[y]=g[x];
x=y;
}
}
void ct(int x,int y,int n)
{
int anc=lca(x,y);
memset(inb,0,sizeof(inb));
sk(x,anc);sk(y,anc);
if(base[x]!=anc) pre[x]=y;
if(base[y]!=anc) pre[y]=x;
for(int i=1;i<=n;i++)
{
if(inb[base[i]]){
base[i]=anc;
if(!inq[i]){
Q.push_back(i);
inq[i]=1;
}
}
}
}
bool dfs(int s,int n){
for(int i=0;i<=n;i++) {pre[i]=-1;inq[i]=0;base[i]=i;}
Q.clear();Q.push_back(s);inq[s]=1;
while(!Q.empty()){
int u=Q.front();Q.pop_front();
for(int v=1;v<=n;v++)
{
if(lk[u][v]&&base[v]!=base[u]&&g[u]!=v)
{
if(v==s||(g[v]!=-1&&pre[g[v]]!=-1)) ct(u,v,n);
else if(pre[v]==-1){
pre[v]=u;
if(g[v]!=-1){
Q.push_back(g[v]);
inq[g[v]]=1;
}
else {
u=v;
while(u!=-1)
{
v=pre[u];
int w=g[v];
g[u]=v;
g[v]=u;
u=w;
}
return 1;
}
}
}
}
}
return 0;
}
int solve()
{
int ans=0;
memset(g,-1,sizeof(g));
for(int i=1;i<=n;i++)
if(g[i]==-1&&dfs(i,n)) ans++;
return ans;
}
int main()
{
int T,cas=1,x,y,c;
scanf("%d",&n);
{
memset(lk,0,sizeof(lk));
int u,v;
while(scanf("%d%d",&u,&v)==2)
{lk[u][v]=lk[v][u]=1;}
int sum=solve();
printf("%d\n",sum*2);
for(int i=1;i<=n;++i){
if(i<g[i])printf("%d %d\n",i,g[i]);
}
}
return 0;
}另外,贴上F题用到的二分图最大匹配高效率的HK算法个人模板(HDU 2389):复杂度O(sqrt(n)*E)#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define maxn 3010
#define INF 1e9
using namespace std;
inline int read()
{
register int c=getchar(),fg=1,sum=0;
while(c>'9'||c<'0') {if(c == '-')fg = -1;c=getchar();}
while(c<='9'&&c>='0'){sum=sum*10+c-'0';c=getchar();}
return fg*sum;
}
int n,m,k,p,ans,sum;
vector<int>G[maxn];
int mx[maxn],my[maxn];
int dx[maxn],dy[maxn];
int dis;
bool used[maxn];
bool findp()
{
queue<int> Q;
dis=INF;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=0;i<n;i++)
if(mx[i]==-1){
Q.push(i);
dx[i]=0;
}
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(dx[u]>dis) break;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(dy[v]==-1)
{
dy[v]=dx[u]+1;
if(my[v]==-1) dis=dy[v];
else
{
dx[my[v]]=dy[v]+1;
Q.push(my[v]);
}
}
}
}
return dis!=INF;
}
bool dfs(int u)
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!used[v]&&dy[v]==dx[u]+1)
{
used[v]=1;
if(my[v]!=-1&&dy[v]==dis) continue;
if(my[v]==-1||dfs(my[v]))
{
my[v]=u;
mx[u]=v;
return 1;
}
}
}
return 0;
}
int solve()
{
int ans=0;
memset(mx,-1,sizeof(mx));
memset(my,-1,sizeof(my));
while(findp())
{
memset(used,0,sizeof(used));
for(int i=0;i<n;i++)
if(mx[i]==-1&&dfs(i)) ans++;
}
return ans;
}
struct node{
int x,y,s;
}n1[maxn],n2[maxn];
int col(node a,node b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int main()
{
int T,t,cas=0;
T=read();
while(T--)
{
++cas;
t=read();
n=read();
for(int i=0;i<=n;i++) G[i].clear();
for(int i=0;i<n;i++)
scanf("%d%d%d",&n1[i].x,&n1[i].y,&n1[i].s);
m=read();
for(int i=0;i<m;i++)
scanf("%d%d",&n2[i].x,&n2[i].y);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(col(n1[i],n2[j])<=n1[i].s*n1[i].s*t*t)
G[i].push_back(j);
printf("Scenario #%d:\n",cas);
printf("%d\n\n",solve());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM 带花树算法