再不做题就老了,这个假期就这么地了
1.POJ 2186
题意:有n头牛和m个有向关系表示两个牛有暧昧关系,牛还都挺喜欢自己的,问你有多少牛是被全体喜欢的。
理解:一看到全体就知道要求两两可达的强连通分量,要是只有一个联通分量就说明每个牛都和其他牛暧昧,多余一个联通分量那就要看他们是不是连成串,穿成串那最后一个出度为0的就是牛中最high的牛群,但要是有个出度大于1或存在2个出度为0的联通分量,就没有那么好的牛了,所以Tarjan对图分析一遍,得到缩的点之间的出度关系。
#include <algorithm> #include <vector> #include <stack> #include <iostream> using namespace std; const int MAXN = 100002; int in[MAXN], out[MAXN]; vector<int> G[MAXN]; int dfn[MAXN],low[MAXN],belong[MAXN],belong_cnt[MAXN]; int Count,n,m,cnt; bool instack[MAXN]; stack <int>stap; void init(){ Count=cnt=0; memset(dfn,0,sizeof(dfn)); memset(belong,0,sizeof(belong)); memset(instack,0,sizeof(instack)); memset(belong_cnt,0,sizeof(belong_cnt)); } void tarjan(int x){ int i; dfn[x]=low[x]=++cnt; stap.push(x); instack[x]=1; for(i=0;i<G[x].size();i++){ int v=G[x][i]; if(!dfn[v]){ tarjan(v); low[x]=min(low[v],low[x]); }else if(instack[v]) low[x]=min(dfn[v],low[x]); } if(low[x]==dfn[x]){ Count++; while(1){ int tmp=stap.top(); stap.pop(); belong[tmp]=Count; belong_cnt[Count]++; instack[tmp]=0; if(tmp==x) break; } } } void work(){ init(); for(int i=0;i<n;i++) if(!dfn[i]) tarjan(i); } void Topsort(){ memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); for (int u = 0; u < n; u++) for (int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if (belong[u] != belong[v]){ in[belong[v]] ++; out[belong[u]] ++; } } } int main(){ int x, y; while(~scanf("%d%d", &n, &m)){ for (int i = 0; i <= n; i++) G[i].clear(); while(m--){ scanf("%d%d", &x, &y); x--; y--; G[x].push_back(y); } work(); if(Count == 1) {printf("%d\n", n);continue;} Topsort(); int c = 0,ans=0; for (int i = 1; i <=Count; i++){ if (out[i] == 0) c++, ans=belong_cnt[i]; } if(c>1) printf("0\n"); else printf("%d\n", ans); } return 0; }
2.POJ 3020
题意:有些格子中的点,要我们用最少的可以覆盖两个相邻点的圈,覆盖所有的点。
理解:http://www.cnblogs.com/updateofsimon/p/3441343.html 最小路径覆盖问题,将每个点拆成两个点一左一右,相邻的点连线,求个最大匹配,每2个表示一种匹配,所以结果就是 点个数 - 最大匹配/2
#include <cstdio> #include <cstring> #define MAXN 405 int point[41][11]; int G[MAXN][MAXN],link[MAXN],used[MAXN],n,m; bool path(int u) { for(int i=1;i<=n;i++) if(G[u][i] && !used[i]) { used[i] = 1; if(link[i]==-1 || path(link[i])) { link[i] = u; return true; } } return false; } void hungary() { int ans = 0; memset(link,-1,sizeof(link)); for(int i=1;i<=n;i++) { memset(used,0,sizeof(used)); if(path(i)) ans++; } printf("%d\n", n-ans/2); } int main() { int T; int x,y; int dir[4][2]={0,-1,0,1,-1,0,1,0}; scanf("%d",&T); while(T--) { n = 0; char ch; scanf("%d%d",&x,&y); memset(point,0,sizeof(point)); memset(G,0,sizeof(G)); for(int i = 0; i < x; i++) { getchar(); for (int j = 0; j < y; j++) { ch=getchar(); if (ch=='*') point[i][j] = ++n; } } for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { if(point[i][j]) for (int d = 0; d < 4; d++) if(i+dir[d][0]>= 0 && i+dir[d][0] < x && j+dir[d][1] >= 0 && j+dir[d][1] < y) if(point[i+dir[d][0]][j+dir[d][1]]) G[point[i][j]][point[i+dir[d][0]][j+dir[d][1]]] = 1; } } hungary(); } return 0; }