1.hdu1045
题意:给出一张图,图中‘X‘表示wall,‘.‘表示空地,可以放置blockhouse
同一条直线上只能有一个blockhouse,除非有wall隔开,问在给出的图中
最多能放置多少个blockhouse
每个边界与X都可以看成是点,.是边连的是离它最近的上面左面的两个边或者X
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;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(!vst[v]&&dy[v]==dx[u]+1) { vst[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 MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa = 40; char mp[maxa][maxa]; int num[maxa][maxa]; int main(){ int n; while(scanf("%d", &n), n){ for(int i = 0; i <= n; i++){ for(int k = 0; k <= n; k++){ mp[i][k] = ‘X‘; } } for(int i = 1; i <= n; i++){ scanf("%s", mp[i]+1); } /*for(int i = 0; i <= n; i++){ printf("%s\n", mp[i]); }*/ int nn = 0; for(int i = 0;i <= n; i++){ for(int k = 0; k <= n; k++){ if(mp[i][k] == ‘X‘) num[i][k] = nn++; } } for(int i = 0; i < nn; i++){ g[i].clear(); } for(int i = 1 ;i <= n; i++){ for(int k = 1; k <= n; k++){ int x, y; if(mp[i][k] == ‘.‘){ for(int j = k-1; j >= 0; j--){ if(mp[i][j] == ‘X‘){ x = num[i][j]; break; } } for(int j = i-1; j >= 0; j--){ if(mp[j][k] == ‘X‘){ y = num[j][k]; break; } } //printf("%d %d\n", x, y); g[x].push_back(y); } } } Nx = nn; printf("%d\n", MaxMatch()); } }
2.hdu3605
题意:有 n 个人选择 m 个星球居住,选择情况和星球居住上限有限制,问是否能全部满足要求。
状态压缩+二分图
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define MAXM 555555 #define MAXN 2222 struct Edge{ int v,cap,next; }edge[MAXM]; int pre[MAXN]; int cur[MAXN]; int head[MAXN]; int level[MAXN]; int gap[MAXN]; int n,m; int NV,NE; void init(){ NE = 0; memset(head, -1, sizeof(head)); } int SAP(int vs,int vt){ memset(pre,-1,sizeof(pre)); memset(level,0,sizeof(level)); memset(gap,0,sizeof(gap)); for(int i=0;i<=NV;i++)cur[i]=head[i]; int u=pre[vs]=vs,maxflow=0,aug=-1; gap[0]=NV; while(level[vs]<NV){ loop: for(int &i=cur[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].cap&&level[u]==level[v]+1){ aug==-1?aug=edge[i].cap:(aug=min(aug,edge[i].cap)); pre[v]=u; u=v; if(v==vt){ maxflow+=aug; for(u=pre[u];v!=vs;v=u,u=pre[u]){ edge[cur[u]].cap-=aug; edge[cur[u]^1].cap+=aug; } aug=-1; } goto loop; } } int minlevel=NV; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].cap&&minlevel>level[v]){ cur[u]=i; minlevel=level[v]; } } gap[level[u]]--; if(gap[level[u]]==0)break; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } return maxflow; } void addedge(int u,int v,int cap,int cc=0){ //printf("*%d %d %d\n", u, v, cap); edge[NE].cap=cap;edge[NE].v=v; edge[NE].next=head[u];head[u]=NE++; edge[NE].cap=cc;edge[NE].v=u; edge[NE].next=head[v];head[v]=NE++; } int num[(1<<11) + 100]; int main(){ int n, m; while(scanf("%d%d", &n, &m)!=EOF){ //将所有的点压缩到1~(1<<m) - 1 num 表示这样的人有多少 init(); memset(num, 0, sizeof(num)); for(int i =0;i < n; i++){ int id = 0; for(int k = 0; k < m; k++){ int x; scanf("%d", &x); if(x){ id += 1<<k; } } num[id] ++; } for(int i = 0;i < m; i++){ int x; scanf("%d", &x); num[(1<<m) + i] = x; //星球的点变成(1<<m) + i num表示每个星球能够承载的人数 } int src = (1<<m) +m + 1; int sink = (1<<m) + m +2; NV = sink+1; for(int i = 0;i < (1<<m); i++){ addedge(src, i, num[i]); //从起点到每种人建立一条人数的边 for(int k = 0; k < m;k ++){ if((1<<k) & i){ addedge(i,(1<<m) + k, num[i]); //每种人到对应的每个星球都建立一条人数的边 } } } for(int i =0 ;i < m; i++){ addedge(i+(1<<m), sink, num[i+(1<<m)]); //星球到终点建立一条星球能承载最大人数的边 } //printf("%d\n", SAP(src, sink)); if(SAP(src, sink) == n) printf("YES\n"); else printf("NO\n"); } }
3.hdu 5093
//二分图匹配(Hopcroft-Carp的算法)。 /* 初始化:g[][]邻接矩阵 调用:res=MaxMatch(); Nx,Ny要初始化!!! 时间复杂大为 O(V^0.5 E) 适用于数据较大的二分匹配 需要queue头文件 ********************************************** */ #include<iostream> #include<string.h> #include<queue> #include<stdio.h> #include<vector> using namespace std; const int MAXN=3000; const int INF=1<<28; int Mx[MAXN],My[MAXN],Nx,Ny; vector<int> g[MAXN]; int dx[MAXN],dy[MAXN],dis; bool vst[MAXN]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;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(!vst[v]&&dy[v]==dx[u]+1) { vst[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 MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; } const int maxa = 400; char mp[maxa][maxa]; int num[maxa][maxa]; int main(){ int n, m; int t; scanf("%d", &t); while(t--){ scanf("%d%d", &n, &m); for(int i = 0; i <= n; i++){ for(int k = 0; k <= m; k++){ mp[i][k] = ‘#‘; } } for(int i = 1; i <= n; i++){ scanf("%s", mp[i]+1); } /*for(int i = 0; i <= n; i++){ printf("%s\n", mp[i]); }*/ int nn = 0; for(int i = 0;i <= n; i++){ for(int k = 0; k <= m; k++){ if(mp[i][k] == ‘#‘) num[i][k] = nn++; } } for(int i = 0; i < nn; i++){ g[i].clear(); } for(int i = 1 ;i <= n; i++){ for(int k = 1; k <= m; k++){ int x, y; if(mp[i][k] == ‘*‘){ for(int j = k-1; j >= 0; j--){ if(mp[i][j] == ‘#‘){ x = num[i][j]; break; } } for(int j = i-1; j >= 0; j--){ if(mp[j][k] == ‘#‘){ y = num[j][k]; break; } } //printf("%d %d\n", x, y); g[x].push_back(y); } } } Nx = nn; printf("%d\n", MaxMatch()); } }
时间: 2024-10-11 16:53:41