清明节也不能懈怠
虽然已经打了好久了隔膜了
但是你说不做题目也是不行的啊
今天学了一个公式:DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中的最大匹配数.
感觉网上的证明也不太好,yy了一下自己的证明
我的证明是这样的:
。。。。。。。。
先说怎么做
直接每个DAG上的点拆点然后建二分图,原点和S连,然后拆出的点和T连跑最大匹配
然后我们可以发现,DAG上的某一条路可以对应一个所建的二分图中的一个匹配
同时可以得出一个公式 DAG路径覆盖可以=对应二分图中的某一个匹配
然后我要证 DAG路径覆盖数=DAG图中的节点数-对应二分图中的某一个匹配
是这样的,我假设一条路径是a->b,b->c,c->d对应的二分图上是a->b拆出来的点,b->c拆出来的点,c->d拆出来的点
然后相当于原图上每一条路径假设包含n个点,那么就是在图上的n-1个匹配
所以每一条路径的产生,二分图匹配就会拆一个点,所以DAG路径覆盖可以=对应二分图中的某一个匹配
然后我们要求的是DAG的最小路径覆盖数
只要二分图中的匹配数最大即可
证明完毕,不知道有没有什么疏漏有的请帮忙讲出
然后知道了以上几点,很容易做这题了,就是构图跑最大匹配然后减一减就可以辣
下面是代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 2503
using namespace std;
int a[2503][2503],lk[2503],f[2503][2503],num[2503][2503];
int vis[2503];
int dx[5],dy[5];
char s[503];
int n,m,r,c,sum,ans,id;
int tim;
bool find(int x){
for(int i=1;i<=id;i++){
if(a[x][i]&&vis[i]!=tim){
vis[i]=tim;
if(!lk[i]||find(lk[i])){
lk[i]=x;
return 1;
}
}
}
return 0;
}
int main(){
cin>>n>>m>>r>>c;
id=0;
for(int i=1;i<=n;i++){
cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='.'){
f[i][j+1]=1,num[i][j+1]=++id;
}else{
f[i][j+1]=0;
}
}
}
dx[0]=r; dx[1]=r; dx[2]=c; dx[3]=c;
dy[0]=c; dy[1]=-c; dy[2]=r; dy[3]=-r;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(f[i][j]){
for(int k=0;k<4;k++){
int x=i+dx[k],y=j+dy[k];
if(x<1||x>n||y<1||y>m){
continue;
}
if(f[x][y]){
a[num[i][j]][num[x][y]]=1;
}
}
}
}
}
for (int i=1;i<=id;i++){
tim++;
if(find(i)){
ans++;
}
}
cout<<(id-ans)<<endl;
return 0;
}