HDU 1281
由于每行最多放一个,每列最多放一个(不能放置的位置不影响攻击,就是因为没注意这句话,把这题当做行列覆盖模型做了好久0.0)
所以把行列直接当做二分图X和Y集,可以放置的点的行列连边,求出的完备匹配就是第二个答案。
至于第一个答案求关键点,就枚举删除一条边能否任然得到完备匹配,若不行,则是关键点。
我的代码c++会WA,不知道为什么,求教啊。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int mp[105][105]; int to[105]; bool vis[105]; int n; int dfs(int k) { for(int i=1;i<=n;i++) { if(!vis[i]&&mp[k][i]) { vis[i]=1; if(to[i]==-1||dfs(to[i])) { to[i]=k; return 1; } } } return 0; } int a[100090],b[100900]; int main() { int m,k,ca=1; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { memset(mp,0,sizeof(mp)); for(int i=1;i<=k;i++) { scanf("%d%d",&a[i],&b[i]); mp[a[i]][b[i]]=1; } int ans=0; memset(to,-1,sizeof(to)); for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); ans+=dfs(i); } int ans2=0,tot=0; for(int i=1;i<=k;i++) { ans2=0; mp[a[i]][b[i]]=0; memset(to,-1,sizeof(to)); for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); ans2+=dfs(i); } if(ans2!=ans) tot++; mp[a[i]][b[i]]=1; } printf("Board %d have %d important blanks for %d chessmen.\n",ca++,tot,ans); } return 0; }
POJ 2062
第一个人按顺序出牌,第二个人重新排列后出牌,求最多得分。
很容易想到的二分图匹配,建图时写个函数比较一下牌的大小就够了。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int mp[105][105]; int to[555]; bool vis[555]; char s[10]; char h[500]; int n; int dfs(int k) { for(int i=0;i<n;i++) { if(!vis[i]&&mp[k][i]) { vis[i]=1; if(to[i]==-1||dfs(to[i])) { to[i]=k; return 1; } } } return 0; } bool cmp(char *sa,char *sb) { if(h[sa[0]]==h[sb[0]]) return h[sa[1]]>h[sb[1]]; return h[sa[0]]>h[sb[0]]; } char sa[105][5],sb[105][5]; int main() { h['H']=3; h['S']=2; h['D']=1; h['C']=0; for(int i='2';i<='9';i++) h[i]=i-'2'; h['T']=8; h['J']=9; h['Q']=10; h['K']=11; h['A']=12; int cas; scanf("%d",&cas); while(cas--) { memset(mp,0,sizeof(mp)); memset(to,-1,sizeof(to)); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s",sa[i]); } for(int i=0;i<n;i++) { scanf("%s",sb[i]); } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(cmp(sb[j],sa[i])) mp[j][i]=1; } } int ans=0; for(int i=0;i<n;i++) { memset(vis,0,sizeof(vis)); ans+=dfs(i); } printf("%d\n",ans); } return 0; }
HDU 2119
行列分为二分图,若相交位置有1则连一条容量为INF的边,其他边容量为1,最小割就是消除所有1的解
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #define INF 0x7fffffff #define maxn 22222 using namespace std; int n,m; int en; int st,ed; //源点和汇点 int dis[maxn] ;//dis[i],表示 到 原点 s 的 层数 int que[9999999]; struct edge { int to,c,next; }; edge e[9999999]; int head[maxn]; void add(int a,int b,int c) { e[en].to=b; e[en].c=c; e[en].next=head[a]; head[a]=en++; e[en].to=a; e[en].c=0; e[en].next=head[b]; head[b]=en++; } int bfs() { memset(dis,-1,sizeof(dis)); dis[st]=0; int front=0,rear=0; que[rear++]=st; while(front<rear) { int j=que[front++]; for(int k=head[j];k!=-1;k=e[k].next) { int i=e[k].to; if(dis[i]==-1&&e[k].c) { dis[i] = dis[j]+ 1 ; que[rear++]=i; if(i==ed) return true; } } } return false; } int dfs(int x,int mx) { int i,a; if(x==ed) return mx ; int ret=0; for(int k=head[x];k!=-1&&ret<mx;k=e[k].next) { if(e[k].c&&dis[e[k].to]==dis[x]+1) { int dd=dfs(e[k].to,min(e[k].c,mx-ret)); e[k].c-=dd; e[k^1].c+=dd; ret+=dd; } } if(!ret) dis[x]=-1; return ret; } void init() { en=0; st=0; //源 ed=n+m+10; //汇 memset(head,-1,sizeof(head)); } void build() { int x,y,z; for(int i=1;i<=n;i++) add(st,i,1); for(int j=1;j<=m;j++) add(j+n,ed,1); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&x); if(x==1) add(i,j+n,INF); } } } int dinic() { int tmp=0; int maxflow=0; while(bfs()) { while(tmp=dfs(st,INF)) maxflow+=tmp; } return maxflow; } int main() { while(scanf("%d",&n)&&n) { scanf("%d",&m); init(); build(); printf("%d\n",dinic()); } }