题意:
给定m,n,下面是m个棍子的横坐标,(题目中可能不是棍子是扑克,不过差不多),这种棍子只能横着放,即占用 x,y 和 x+1,y;
下面是n个竖着放置的棍子,只占用 x,y 和x,y+1;(不能往下啊)
,问可以去掉一些棍子,最大有多少棍子没有重叠。
一开始以为是水题,后来就是各种wa,我也想不到是网络流,后来写了一个dinic,也是错误百出。
错误1 没有把vector给初始化。
错误2 maxn开小了。
图论太神奇了。amazing!
此题也是 dinic模板题。属于比较简单的。
或者用二分图,上匈牙利算法;
通过最大匹配来求最大独立集。
和网络流的思路差不多,这些东西,挑战程序设计竞赛中都有讲
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
using namespace std;
const int maxn=2000;
vector<int>G[maxn];
int n,m;
void add(int u,int v)
{ G[u].push_back(v);
G[v].push_back(u);
//printf("\n%d******%d\n",u,v);
}
int used[maxn];
int match[maxn];
bool dfs(int v)//这次dfs的点
{
used[v]=true;
for(int i=0;i<G[v].size();i++)
{ int x=G[v][i]; int w=match[x];
if(w<0||!used[w]&&dfs(w))
{ match[v]=x;
match[x]=v;
return true;
}
}
return false;
}
int matching()
{ int res=0;
memset(match,-1,sizeof(match));
for(int v=1;v<=m;v++)
{ if(match[v]<0)
{ memset(used,0,sizeof(used));
if(dfs(v))
{ res++;
}
}
}
printf("%d\n",m+n-res);
}
int main()
{
int a,b;
pair<int,int>x[maxn];
while(~scanf("%d%d",&m,&n),m+n)
{ for(int i=0;i<maxn;i++)
G[i].clear();
for(int i=1;i<=m;i++)
{ scanf("%d%d",&a,&b);
x[i]=make_pair(a,b);
}
for(int i=m+1;i<=m+n;i++)
{ scanf("%d%d",&a,&b);
x[i]=make_pair(a,b);
}
//for(int i=1;i<=m+n;i++)
//{ cout<<x[i].first<<x[i].second<<endl;
//}
for(int i=1;i<=m;i++)
for(int j=m+1;j<=m+n;j++)
{ if(x[i].first==x[j].first&&x[i].second==x[j].second)
{add(i,j);
//cout<<i<<"**"<<j<<endl;
}
if(x[i].first==x[j].first&&x[i].second==x[j].second+1)
{add(i,j);
//cout<<i<<"**"<<j<<endl;
}
if(x[i].first+1==x[j].first&&x[i].second==x[j].second)
{add(i,j);
//cout<<i<<"**"<<j<<endl;
}
if(x[i].first+1==x[j].first&&x[i].second==x[j].second+1)
{add(i,j);
//cout<<i<<"**"<<j<<endl;
}
}
/*for(int i=1;i<=m;i++)
{ for(int j=0;j<G[i].size();j++)
printf("****%d ",G[i][j]);
cout<<endl;
}*/
matching();
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
//具体思路:
/*先建边,怎么可是怎么建边呢,
*/
const int maxn=3000;
struct Node
{
int a,b;
};
Node x[maxn];
Node y[maxn];
int level[maxn];
int iter[maxn];
struct Tree
{ int to,rev,value;
Tree(int a,int b,int c)
{ to=a;
value=b;
rev=c;
}
};
vector<Tree>G[maxn];
int m,n;
void add(int i,int j)
{ G[i].push_back(Tree(j,1,G[j].size()));
G[j].push_back(Tree(i,0,G[i].size()-1));
//顺便也记录了反向边得了;
}
void bfs(int s){
memset(level,-1,sizeof(level));
queue<int>que;level[s]=0;
que.push(s);
while(!que.empty()){
int v=que.front();que.pop();
for(unsigned int i=0;i<G[v].size();i++){
Tree &e=G[v][i];
if(e.value>0&&level[e.to]<0){
level[e.to]=level[v]+1;
que.push(e.to);
}
}
}
}
int dfs(int v,int t,int f){
if(v==t) return f;
for(int &i=iter[v];i<G[v].size();i++){
Tree &e=G[v][i];
if(e.value>0&&level[v]<level[e.to]){
int d=dfs(e.to,t,min(f,e.value));
if(d>0){
e.value-=d;
G[e.to][e.rev].value+=d;
return d;
}
}
}
return 0;
}
int max_flow(int s,int t){
int flow=0;
while(1){
bfs(s);
if(level[t]<0)
{printf("%d\n",m+n-flow);
return 0;
}
memset(iter,0,sizeof(iter));
int f;
while((f=dfs(s,t,0x3f3f3f3f))>0) flow+=f;
}
}
bool check(int d,int f)
{ //printf("%d %d\n%d %d\n",x[d].a,x[d].b,x[f].a,x[f].b);
if(x[d].a==x[f].a&&x[d].b==x[f].b)
return 1;
if(x[d].a==x[f].a&&x[d].b==x[f].b+1)
return 1;
if(x[d].a+1==x[f].a&&x[d].b==x[f].b)
return 1;
if(x[d].a+1==x[f].a&&x[d].b==x[f].b+1)
return 1;
return 0;
}
int main()
{ int a,b;
while(~scanf("%d%d",&m,&n),m+n)
{ for(int x=0;x<maxn;x++)
G[x].clear();
for(int i=1;i<=m;i++)
{ scanf("%d%d",&a,&b);
x[i].a=a;
x[i].b=b;
}
for(int i=1+m;i<=n+m;i++)
{ scanf("%d%d",&a,&b);
x[i].a=a;
x[i].b=b;
}
for(int i=1;i<=m;i++)
{ for(int j=m+1;j<=n+m;j++)
{ if(check(i,j))
{ add(i,j);
//printf("***%d %d\n",i,j);
}
}
} //见图;
for(int i=1;i<=m;i++)
add(m+n+1,i);
for(int j=m+1;j<=n+m;j++)
add(j,m+n+2);
/*for(int i=0;i<=m+n+1;i++)
{for(int j=0;j<G[i].size();j++)
printf("%d ",G[i][j].to);
printf("\n");}*/
max_flow(m+n+1,m+n+2);
}
return
“`
http://blog.csdn.net/dark_scope/article/details/8880547
这是是讲匈牙利的连接,挺好的。