POJ 图算法

图的深度优先遍历和广度优先遍历

poj3278,

 poj2049, poj3083

最短路径算法

poj1860,poj3259,poj1062,poj2253,poj1125,poj2240

最小生成树算法

poj1789,poj2485,poj1258,poj3026

拓扑排序

poj1094, poj3267(DP)poj3687

二分图的最大匹配

poj3041,poj3020

最大流的增广路算法

poj1459,poj3436

                                                    

                                     

   

              

图的深度优先遍历和广度优先遍历

poj3278

简单bfs,话说要加vis滴。话说要剪枝滴。妹的TLE了好几次!纠结啊!  我抽了,刚才居然用bitset试了几遍。不RE才怪。。。

渣代码:

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <queue>
5
6 using namespace std;
7
8 int N, K;
9
10 class node {
11 public:
12 int p;
13 int m;
14 };
15
16 queue<node> q;
17 bool vis[200010];
18
19 void bfs(int p) {
20 while(!q.empty()) q.pop();
21 memset(vis, false, sizeof(vis));
22
23 node t, v;
24 t.p = p; t.m = 0;
25 q.push(t); vis[p] = true;
26
27 while(!q.empty()) {
28 v = q.front(); q.pop();
29
30 if(v.p == K) {printf("%d\n", v.m); return;}
31 t.m = v.m + 1;
32
33 t.p = v.p - 1;
34 if(!vis[t.p] && t.p >= 0) {
35 q.push(t); vis[t.p] = true;
36 }
37
38 if(v.p > K) continue;
39
40 t.p = v.p + 1;
41 if(!vis[t.p]) {
42 q.push(t); vis[t.p] = true;
43 }
44
45 t.p = v.p * 2;
46 if(!vis[t.p]) {
47 q.push(t); vis[t.p] = true;
48 }
49 }
50 }
51
52 int main() {
53 //freopen("data.in", "r", stdin);
54
55 while(~scanf("%d%d", &N, &K)) {
56 bfs(N);
57 }
58 return 0;
59 }

poj 2049

关于这道题,我想说。。。我想砸键盘!!!wa了nnnn次!后来卑鄙的看大牛的代码过的。T_T

抄袭代码

View Code
  1 /*主要思路如下:
2 (1)首先是建图, 由于输入给的都是线段, 但是我们平常处理这类问题都是转换为网格来做的, 因此需要
3 将线段转换为网格.转化的方法是对于每个格子,用其左上角点的坐标来表示这个格子,如果其左上角点的
4 坐标是[i][j],那么这个格子就表示为[i][j].将其四周边界的四条线段归这个格子管.即为每个格子建一
5 个数组round[i][j][4],第三维的四个位置分别表示这四条线段的类型: 0表示空气,1表示墙,2表示是一扇
6 门,这样这个模型就建立好了.
7 (2)其次是bfs的起始点选为Nemo所在的位置,注意要将这个浮点点位置转化为格子的坐标.转化的方法很简
8 单.对于x坐标取整即可,对于y坐标取整+1即可,比如Nemo所在位置为[1.2, 1.3]那么转化为格子的坐标即为:
9 [1, 2].这个坐标即位bfs遍历的起始点
10 (3)遍历的时候如果所走的方向是墙,则不可走.如果是门则将当前总的steps数+1,如果为空气,steps数不变.
11 另外一点就是如何判重.判重不能简单地记录有没有被访问过,而是需要记录到当前格子的最小步骤.如果当
12 前总步骤数小于当前格子的最小步骤数,则更新其最小步骤数并将这个格子加入队列中.
13 (4)遍历的终止位置即为题目中的出发位置[0, 0]*/
14
15 #include <iostream>
16 #include <cstring>
17 #include <cstdio>
18 #include <queue>
19
20 using namespace std;
21
22 const int N = 205;
23 const int inf = ~0u>>2;
24
25 struct situ {
26 int x;
27 int y;
28 int s; //到当前节所走的步数
29 int d; //d表示到当前节点来的商议个节点的方向
30 };
31
32 queue<situ> q;
33
34 int mins;
35 int g[N][N][4];
36 int st[N][N];
37 int dir[4][2] = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
38 // 0上,1下,2左,3右
39 int m, n;
40
41 bool ok(int x, int y) { //看是否越界
42 if(x < 0 || x > 199 || y < 0 || y > 199) return false;
43 return true;
44 }
45
46 void change_D(int i, int &d) { //来向要跟上一个节点的去向正好相反
47 if(i == 0) d = 1;
48 else if(i == 1) d = 0;
49 else if(i == 2) d = 3;
50 else d = 2;
51 }
52
53 void init() {
54 mins = inf;
55 for(int i = 0; i < N; ++i) {
56 for(int j = 0; j < N; ++j) {
57 st[i][j] = inf;
58 }
59 }
60 while(!q.empty()) q.pop();
61 }
62
63 void bfs(int sx, int sy) {
64 init();
65
66 situ t, v;
67 t.x = sx, t.y = sy, t.d = -1; t.s = 0;
68 st[sx][sy] = 0; q.push(t);
69
70 int x, y, d, s, i;
71 int nx, ny, nd, ns;
72 while(!q.empty()) {
73 v = q.front(); q.pop();
74 x = v.x; y = v.y; s = v.s; d = v.d;
75
76 if(x == 0 && y == 0) {
77 //printf("%d %d\n", s, mins);
78 //printf("%d\n", st[x][y]);
79 if(s < mins) mins = s;
80 continue;
81 }
82 for(i = 0; i < 4; i++) {
83 if(i == d || g[x][y][i] == 1) continue;
84 nx = x + dir[i][0];
85 ny = y + dir[i][1];
86 if(!ok(nx, ny)) continue;
87
88 change_D(i, nd);
89 if(g[x][y][i] == 2) ns = s + 1;
90 else ns = s;
91
92 if(ns < st[nx][ny] && ns < mins) {
93 st[nx][ny] = ns;
94 t.x = nx; t.y = ny; t.d = nd; t.s = ns;
95 q.push(t);
96 }
97 }
98 }
99 }
100
101 int main () {
102 //freopen("data.in", "r", stdin);
103
104 int i, j;
105 int x, y, d, t;
106 double a, b;
107 while(~scanf("%d%d", &m, &n)) {
108 if(m == -1 && n == -1) break;
109 memset(g, 0, sizeof(g));
110 for(i = 0; i < m; ++i) {
111 scanf("%d%d%d%d", &x, &y, &d, &t);
112 if(d == 1) {
113 for(j = y + 1; j <= y + t; ++j)
114 g[x][j][2] = g[x-1][j][3] = 1;
115 } else {
116 for(j = x; j < x + t; ++j)
117 g[j][y][0] = g[j][y+1][1] = 1;
118 }
119 }
120
121 for(i = 0; i < n; ++i) {
122 scanf("%d%d%d", &x, &y, &d);
123 if(d == 1) g[x][y+1][2] = g[x-1][y+1][3] = 2;
124 else g[x][y][0] = g[x][y+1][1] = 2;
125 }
126 scanf("%lf%lf", &a, &b);
127 x = a; y = b + 1;
128 if(x < 0 || x > 199 || y < 0 || y > 199) {printf("0\n"); continue;}
129 bfs(x, y);
130 if(mins == inf) printf("-1\n");
131 else printf("%d\n", mins);
132 }
133 return 0;
134 }

 poj 3083

昨天以为是一道巨复杂的模拟加搜索题。然后想各种情况。。。然后就疯掉了。今天看了一下网上的解题报告,方向转的真神了!Orz。

左优先时顺时针,右优先时逆时针。加一个全局变量dir,控制下一步的方向。以左优先为例,这一步向上走,则下一步按顺时针方向转3次,向左走。

右优先同理。。。

关键代码:

View Code
 1 int Left[4][2] = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};
2 int Right[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
3
4 bool inMap(int x, int y) {
5 if(x < 0 || x >= h || y < 0 || y >= w) return false;
6 return true;
7 }
8
9 int dfs_l(int x, int y, int s) { //左优先
10 if(x == ei && y == ej) {
11 return s + 1;
12 }
13 if(!inMap(x, y) || map[x][y] == '#') return 0;
14 dir = (dir + 3) % 4;
15 int tmp;
16 while(1) {
17 tmp = dfs_l(x + Left[dir][0], y + Left[dir][1], s + 1);
18 if(tmp > 0) break;
19 dir = (dir + 1) % 4;
20 }
21 }

最短路径算法

poj 1860

spfa裸模板,话说本菜以前看过的spfa都还给别人了。今天又重新看了一遍。顺便写下模板。。。

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <queue>
5
6 using namespace std;
7
8 const int N = 110;
9 const double inf = ~0u>>2;
10
11 struct node {
12 int from;
13 int to;
14 double c;
15 double r;
16 int next;
17 } g[N<<1];
18
19 int head[N], t;
20 bool inq[N];
21 double dis[N], sum;
22 int n, m, s;
23
24 queue<int> q;
25
26 void add(int u, int v, double r, double c) {
27 g[t].from = u; g[t].to = v; g[t].c = c; g[t].r = r;
28 g[t].next = head[u]; head[u] = t++;
29 }
30
31 void init() {
32 for(int i = 0; i < N; i++) {
33 dis[i] = 0; inq[i] = false;
34 }
35 memset(head, 0, sizeof(head)); t = 1;
36 while(!q.empty()) q.pop();
37 }
38
39 bool spfa() {
40 double c, r;
41 int u, v, i;
42 dis[s] = sum;
43 q.push(s);
44 inq[s] = true;
45
46 while(!q.empty()) {
47 u = q.front();
48 for(i = head[u]; i; i = g[i].next) {
49 v = g[i].to; c = g[i].c; r = g[i].r;
50
51 if(dis[v] < (dis[u] - c) * r) {
52 dis[v] = (dis[u] - c) * r;
53 if(!inq[v]) {
54 q.push(v);
55 inq[v] = true;
56 }
57 }
58 }
59 //printf("%d %lf\n", u, dis[u]);
60 inq[u] = false;
61 q.pop();
62 }
63 //printf("%lf %lf\n", dis[s], sum);
64 return dis[s] > sum;
65 }
66
67 int main() {
68 //freopen("data.in", "r", stdin);
69
70 int i, x, y;
71 double R, C;
72 while(~scanf("%d%d%d%lf", &n, &m, &s, &sum)) {
73 init();
74 for(i = 0; i < m; i++) {
75 scanf("%d%d%lf%lf", &x, &y, &R, &C);
76 add(x, y, R, C);
77 scanf("%lf%lf", &R, &C);
78 add(y, x, R, C);
79 }
80 if(spfa()) puts("YES");
81 else puts("NO");
82 }
83 return 0;
84 }

poj 3259

spfa判断是否有负环,个人还是习惯用邻接表写spfa。。。注意有重边,wa了一次。。

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <queue>
5
6 using namespace std;
7
8 const int N = 510;
9 const int M = 6000;
10 const int inf = ~0u>>2;
11
12 struct node {
13 int to;
14 int val;
15 int next;
16 } g[M];
17
18 int head[N], t;
19 int dis[N];
20 int cnt[N];
21 int d[N][N];
22 bool inq[N];
23 int n, m, w;
24 queue<int> q;
25
26 void init() {
27 while(!q.empty()) q.pop();
28 memset(head, 0, sizeof(head));
29 memset(inq, 0, sizeof(inq));
30 memset(cnt, 0, sizeof(cnt));
31 for(int i = 0; i <= n; ++i) {
32 dis[i] = inf;
33 for(int j = 0; j <= n; ++j)
34 d[i][j] = inf;
35 }
36 t = 1;
37 }
38
39 void add(int u, int v, int z) {
40 g[t].to = v; g[t].val = z; g[t].next = head[u]; head[u] = t++;
41 }
42
43 bool spfa() {
44 int i, u, v, z;
45 q.push(1); inq[1] = true;
46 dis[1] = 0; cnt[1]++;
47
48 while(!q.empty()) {
49 u = q.front();
50 for(i = head[u]; i; i = g[i].next) {
51 v = g[i].to; z = g[i].val;
52 if(dis[v] > dis[u] + z) {
53 dis[v] = dis[u] + z;
54 if(!inq[v]) {
55 cnt[v]++;
56 inq[v] = true;
57 if(cnt[v] > n) return false;
58 q.push(v);
59 }
60 }
61 }
62 inq[u] = false;
63 q.pop();
64 }
65 return true;
66 }
67
68 int main() {
69 //freopen("data.in", "r", stdin);
70
71 int f, x, y, z, i;
72 scanf("%d", &f);
73
74 while(f--) {
75
76 scanf("%d%d%d", &n, &m, &w);
77 init();
78 for(i = 0; i < m; ++i) {
79 scanf("%d%d%d", &x, &y, &z);
80 if(d[x][y] > z) d[x][y] = z;
81 else continue;
82 add(x, y, z);
83 add(y, x, z);
84 }
85 for(i = 0; i < w; ++i) {
86 scanf("%d%d%d", &x, &y, &z);
87 add(x, y, -z);
88 }
89 if(spfa()) puts("NO");
90 else puts("YES");
91 }
92 return 0;
93 }

poj 1062

这题做的想吐!!妹的建图费劲也就算了,还得分等级!!这不是折腾人吗!

思路是加一个源点0,0到每个点i的距离等于i点本来的价格P,然后进行n次spfa,每次限定一个等级Lv[i],保证spfa时搜到的点j,使Lv[i] - Lv[j] <= m && Lv[j] <= Lv[i];

关键代码:

View Code
 1 int spfa() {    //一次spfa
2 queue<int> q;
3 int u, v, w, i;
4
5 for(i = 0; i < N; ++i) dis[i] = inf, inq[i] = false;
6 q.push(0);
7 inq[0] = true;
8 dis[0] = 0;
9
10 while(!q.empty()) {
11 u = q.front(); q.pop();
12 inq[u] = false;
13
14 for(i = 0; i < mp[u].size(); ++i) {
15 v = mp[u][i].y; w = mp[u][i].z;
16
17 if(dis[v] > dis[u] + w && L - lv[v] <= m && lv[v] <= L) {
18 dis[v] = dis[u] + w;
19 if(!inq[v]) {
20 inq[v] = true;
21 q.push(v);
22 }
23 }
24 }
25 }
26 return dis[1];
27 }
28
29 for(i = 1; i <= n; ++i) {
30 L = lv[i];
31 ans = min(ans, spfa());
32 }


poj 2253

二分 + SPFA,开始看错题意了,上去就写Dijkstra,后来仔细一看不是求最短路,或者说是加边权限制的最短路,用spfa水过了。

思路:统计出所有路径的Min和Max,以这两个数为上下界进行二分。

C++小知识,vector型数据调用size()函数直接跟整型的i做比较编译器会警告,最好加上static_cast<int>(),例如: for(i = 0; i < static_cast<int>(mp[u].size()); ++i) 这样编译器就没话说了。哈

ps:个人感觉,遇到double就用eps,用了不会错,不用可能错^_^

代码:

View Code
 1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <cmath>
5 #include <vector>
6 #include <queue>
7
8 using namespace std;
9
10 const int N = 210;
11 const double inf = ~0u>>1;
12 const double eps = 1e-6;
13
14 class Node {
15 public:
16 int v;
17 double z;
18 Node(int a, double b) : v(a), z(b) {};
19 };
20
21 vector<Node> mp[N];
22
23 double x[N], y[N];
24 double dis[N], lim;
25 bool inq[N];
26 int n;
27
28 double Dis(int i, int j) {
29 return sqrt((x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]));
30 }
31
32 void init() {
33 for(int i = 0; i < N; ++i) {
34 x[i] = y[i] = 0;
35 mp[i].clear();
36 }
37 }
38
39 bool spfa() {
40 queue<int> q;
41 int i, u, v;
42 double w;
43 for(i = 0; i < N; ++i) {
44 dis[i] = inf; inq[i] = false;
45 }
46 dis[0] = 0; inq[0] = true;
47 q.push(0);
48
49 while(!q.empty()) {
50 u = q.front(); inq[u] = false; q.pop();
51
52 for(i = 0; i < static_cast<int>(mp[u].size()); ++i) {
53 v = mp[u][i].v; w = mp[u][i].z;
54
55 if(dis[v] > dis[u] + w && w <= lim) {
56 dis[v] = dis[u] + w;
57 if(!inq[v]) {
58 inq[v] = true;
59 q.push(v);
60 }
61 }
62 }
63 }
64 if(dis[1] < inf) return true;
65 else return false;
66 }
67
68 int main() {
69 //freopen("data.in", "r", stdin);
70
71 int i, j, cas = 0;
72 double t, l, r;
73 while(scanf("%d", &n), n) {
74 init();
75 scanf("%lf%lf", &x[0], &y[0]);
76 l = inf; r = -1;
77 for(i = 1; i < n; ++i) {
78 scanf("%lf%lf", x + i, y + i);
79 for(j = 0; j < i; ++j) {
80 t = Dis(i, j);
81 l = min(t, l); r = max(t, r);
82 mp[i].push_back(Node(j, t));
83 mp[j].push_back(Node(i, t));
84 // printf("%d %d %lf\n", i, j, t);
85 }
86 }
87
88 while(1) {
89 if(!(r - l > eps)) break;
90 lim = (l + r) / 2;
91
92 if(spfa()) r = lim;
93 else l = lim;
94 }
95 printf("Scenario #%d\nFrog Distance = %.3f\n", ++cas, l);
96 putchar('\n');
97 }
98 return 0;
99 }


poj 1125

用floyd扫一遍,然后找开始节点和最大长度

poj 2240

把思路想错了,结果好几次TLE,以每一种货币为始点进行spfa,如果出现始点第二次入队列,说明已经有利润,dis[]初始化为0

渣代码:

View Code
  1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <string>
5
6 using namespace std;
7
8 const int N = 50;
9 const double eps = 1e-6;
10
11 string ts[N];
12
13 struct node {
14 int v;
15 double w;
16 int next;
17 }g[N*N];
18
19 int head[N], t, n;
20 double dis[N];
21 int q[N<<11];
22 bool inq[N];
23
24 int findp(string t) {
25 int i;
26 for(i = 0; i < n; ++i) {
27 if(t == ts[i]) return i;
28 }
29 return -1;
30 }
31
32 void init() {
33 memset(head, 0, sizeof(head));
34 for(int i = 0; i < N; ++i) ts[i].clear();
35 t = 1;
36 }
37
38 void add(int u, int v, double w) {
39 g[t].v = v; g[t].w = w; g[t].next = head[u]; head[u] = t++;
40 }
41
42 bool spfa(int s) {
43 int i, u, v, f = 0, r = 0;
44 double w;
45
46 for(i = 0; i < N; ++i) {
47 dis[i] = 0; inq[i] = false;
48 q[i] = 0;
49 }
50 q[r++] = s; inq[s] = true; dis[s] = 1;
51
52 while(f < r) {
53 u = q[f]; f++; inq[u] = false;
54
55 for(i = head[u]; i; i = g[i].next) {
56 v = g[i].v; w = g[i].w;
57 if(dis[u] * w - dis[v] > eps) {
58 dis[v] = dis[u] * w;
59 if(!inq[v]) {
60 inq[v] = true;
61 if(v == s) return true;
62 q[r++] = v;
63 }
64 }
65 }
66
67 }
68 return false;
69 }
70
71 int main() {
72 //freopen("data.in", "r", stdin);
73
74 int m, i, x, y, cas = 0;
75 double rate;
76 string t1, t2;
77 while(scanf("%d", &n), n) {
78 init();
79 for(i = 0; i < n; ++i) {
80 cin >> ts[i];
81 }
82 scanf("%d", &m);
83 bool flag = false;
84 while(m--) {
85 cin >> t1 >> rate >> t2;
86 x = findp(t1); y = findp(t2);
87 if(x == y && rate - 1 > eps) flag = true;
88 if(!flag) add(x, y, rate);
89 //printf("%d %d %lf\n", x, y, rate);
90 }
91 printf("Case %d: ", ++cas);
92 if(flag) {puts("Yes"); continue;}
93
94 for(i = 0; i < n; ++i) {
95 if(spfa(i)) {puts("Yes"); flag = true; break;}
96 }
97 if(!flag) puts("No");
98 }
99 return 0;
100 }


最小生成树算法

poj 1789

以前做过这道题,是用prim做的,本来以为这题用kruskal做会快一些,妹的!没想到G++ TLE,C++ 1000+ms。。。

poj 2485

额看错题意了。。。神啊!是让求最小生成树上最长的一条边,不是保证最长边最小构成最小生成树。

poj 1258

裸prim,没有看题,看数据猜过去的,把poj2485的改改就行。

poj 3026

题意很费解,我是到网上搜的思路。大概是给一个图,然后给一些S, A0, A1, A2。。。。求每一对(S,A1), (A0, A2)等两两间的距离,建图。然后求最小生成树。

可以用bfs先把两两间的距离搜出来,然后就是套MST模板了。

贴代码(建图是参考大牛的):

View Code
  1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <queue>
6
7 using namespace std;
8
9 const int N = 110;
10 const int inf = ~0u>>2;
11
12 struct Node {
13 int x;
14 int y;
15 int w;
16 Node(int a = 0, int b = 0, int c = 0) : x(a), y(b), w(c) {};
17 };
18
19 char map[N][N];
20
21 int mp[N][N];
22 int g[N][N];
23 int low[N];
24
25 bool vis[N][N];
26 bool f[N];
27 int x, y, n;
28
29 int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
30
31 void bfs(int si, int sj) {
32 int i;
33 memset(vis, 0, sizeof(vis));
34 queue<Node> q;
35
36 vis[si][sj] = true;
37 q.push(Node(si, sj, 0));
38
39 Node u, v;
40 while(!q.empty()) {
41 u = q.front(); q.pop();
42
43 for(i = 0; i < 4; ++i) {
44 v.x = u.x + dir[i][0];
45 v.y = u.y + dir[i][1];
46
47 if(!vis[v.x][v.y] && mp[v.x][v.y] >= -1) {
48 v.w = u.w + 1;
49 vis[v.x][v.y] = true;
50
51 if(mp[v.x][v.y] >= 0) {
52 //printf("%d %d %d ** %d %d\n", mp[si][sj], mp[v.x][v.y], v.w, si, sj);
53 g[mp[si][sj]][mp[v.x][v.y]] = v.w;
54 }
55 q.push(v);
56 }
57 }
58 }
59 }
60
61 int prim() {
62 int i, j, min, flag, sum = 0;
63 for(i = 0; i < n; ++i) {
64 low[i] = g[0][i]; f[i] = false;
65 }
66
67 f[0] = true; low[0] = 0;
68
69 for(i = 1; i < n; ++i) {
70 min = inf; flag = 0;
71
72 for(j = 1; j < n; ++j) {
73 if(min > low[j] && !f[j]) {
74 min = low[j];
75 flag = j;
76 }
77 }
78
79 f[flag] = true;
80 sum += low[flag];
81
82 for(j = 1; j < n; ++j) {
83 if(g[flag][j] < low[j] && !f[j]) {
84 low[j] = g[flag][j];
85 }
86 }
87 }
88 return sum;
89 }
90
91 int main() {
92 //freopen("data.in", "r", stdin);
93
94 int t, i, j;
95 char buffer[N];
96 scanf("%d", &t);
97 while(t--) {
98 scanf("%d%d", &x, &y); gets(buffer); //这里discuss里边有讲,貌似是后台数据的问题
99 n = 0;
100 for(i = 0; i < y; ++i) {
101 gets(map[i]);
102 for(j = 0; j < x; ++j) {
103 switch (map[i][j]) {
104 case '#': mp[i][j] = -2; break;
105 case ' ': mp[i][j] = -1; break;
106 case 'A':
107 case 'S': mp[i][j] = n++; break;
108 }
109 }
110 }
111 /*for(i = 0; i < y; ++i) {
112 for(j = 0; j < x; ++j)
113 printf("%3d", mp[i][j]);
114 cout << endl;
115 }*/
116 for(i = 0; i < y; ++i) {
117 for(j = 0; j < x; ++j) {
118 if(mp[i][j] >= 0)
119 bfs(i, j);
120 }
121 }
122 /*for(i = 0; i < n; ++i) {
123 for(j = 0; j < n; ++j) {
124 printf("%d ", g[i][j]);
125 }
126 cout << endl;
127 }*/
128 printf("%d\n", prim());
129 }
130 return 0;
131 }


拓扑排序

poj 1094

每读入一组数据进行一次toposort,如果toposort过程中出现没有入度为0的点,则说明“Inconsistency found after xxx relations."如果一直存在多个入度为0的点,则说明"Sorted sequence cannot be determined."。否则,则为有解的情况,记录并出去可行解就可以。

ps:今天感觉好累。

渣代码:

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4
5 using namespace std;
6
7 const int N = 30;
8
9 int deg[N], cnt[N];
10 int g[N][N], ans[N], n;
11
12 int toposort() {
13 int i, j, u, num, t = 0;
14 bool flag;
15 for(i = 0; i < n; ++i) {
16 cnt[i] = deg[i];
17 //printf("%d ", cnt[i]);
18 }
19 //cout << endl;
20 flag = false;
21 memset(ans, 0, sizeof(ans));
22 for(i = 0; i < n; ++i) {
23 num = 0;
24 for(j = 0; j < n; j++) {
25 if(cnt[j] == 0) {
26 u = j;
27 num++;
28 }
29 }
30 //printf("%d\n", num);
31 if(num == 0) return 0;
32 if(num > 1) flag = true;
33 cnt[u] = -1; ans[t++] = u;
34 for(j = 0; j < n; ++j) {
35 if(g[u][j]) {
36 cnt[j]--;
37 }
38 }
39 }
40 if(flag) return -1;
41 return 1;
42 }
43
44 int main() {
45 //freopen("data.in", "r", stdin);
46
47 int m, i, j, x, y, r;
48 bool f;
49 char s[N];
50
51 while(~scanf("%d%d", &n, &m)) {
52 if(n + m == 0) break;
53 f = false;
54 memset(deg, 0, sizeof(deg));
55 memset(g, false, sizeof(g));
56 for(i = 0; i < m; ++i) {
57 scanf("%s", s);
58 x = s[0] - 'A';
59 y = s[2] - 'A';
60 if(f) continue;
61 deg[y]++;
62 g[x][y] = true;
63 r = toposort();
64 if(r == 0) {
65 printf("Inconsistency found after %d relations.\n", i + 1);
66 f = true;
67 }
68 if(r == 1) {
69 printf("Sorted sequence determined after %d relations: ", i + 1);
70 for(j = 0; j < n; ++j) printf("%c", ans[j] + 'A');
71 printf(".\n");
72 f = true;
73 }
74 }
75 if(!f) puts("Sorted sequence cannot be determined.");
76 }
77 return 0;
78 }


poj 3267

这是道DP的题,以前做过。详见http://www.cnblogs.com/vongang/archive/2011/10/06/2200131.html#


二分图的最大匹配

poj 3687

很裸的最小点覆盖,直接按G[a][b+1] = true;建图。

poj 3020

最大独立集的变形,把一维的编程二维的了。

思路是出现*的坐标标为true,然后一每个为true的坐标为起点用匈利亚算法确定是否有增广路存在。注意,这样统计出来的数据是最大二分匹配的二倍,因为默认的看成了无向图。

result = 为true的结点数 - 最大二分匹配。

View Code
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int N = 50;

bool g[N][N];
bool usd[N][N];
int lx[N][N], ly[N][N];
int h, w;
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

bool can(int x, int y) {
int a, b, i;
for(i = 0; i < 4; ++i) {
a = x + dir[i][0];
b = y + dir[i][1];
if(!usd[a][b] && g[a][b]) {
usd[a][b] = true;
if((lx[a][b] == -1 && ly[a][b] == -1) || can(lx[a][b], ly[a][b])) {
lx[a][b] = x;
ly[a][b] = y;
return true;
}
}
}
return false;
}

int main() {
//freopen("data.in", "r", stdin);

int i, j, t;
int n, cnt;
char c;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &h, &w);
getchar();
memset(g, false, sizeof(g));
for(n = 0, i = 1; i <= h; ++i) {
for(j = 1; j <= w; ++j) {
scanf("%c", &c);
//printf("%c", c);
if(c == '*') {g[i][j] = true; n++;}
// printf("%d", g[i][j]);
}
getchar();
// cout << endl;
}
cnt = 0;
memset(lx, -1, sizeof(lx));
memset(ly, -1, sizeof(ly));
for(i = 1; i <= h; ++i) {
for(j = 1; j <= w; ++j) {
if(g[i][j]) {
memset(usd, 0, sizeof(usd));
if(can(i, j)) cnt++;
}
}
}
printf("%d\n", n - cnt/2);
}
return 0;
}


最大流的增广路算法

poj 1459

所有的p连向源点,所有的c连向汇点。以前用EK写过,1600+ms,今天用Dinic写的。420+ms。Dinic的优化很明显,呵呵

View Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;

const int N = 110;
const int inf = ~0u>>1;

int g[N][N];
int layer[N];
bool vis[N];
int S, T;

bool Layer() {
queue<int> q;
memset(layer, -1, sizeof(layer));
q.push(S); layer[S] = 1;

int i, v;
while(!q.empty()) {
v = q.front(); q.pop();
for(i = 0; i <= T; ++i) {
if(g[v][i] && layer[i] == -1) {
layer[i] = layer[v] + 1;
if(i == T) {for(;!q.empty(); q.pop()); return true;}
q.push(i);
}
}
}
return false;
}

int Dinic() {
deque<int> q;
int i, v, p;
int vs, ve, Min, sum = 0;

while(Layer()) {
memset(vis, 0, sizeof(vis));
q.push_back(S);
vis[S] = true;

while(!q.empty()) {
v = q.back();
if(v != T) {
for(i = 0; i <= T; ++i) {
if(g[v][i] && !vis[i] && layer[i] == layer[v] + 1) {
vis[i] = true;
q.push_back(i); break;
}
}
if(i > T) q.pop_back();
} else {
Min = inf;
for(i = 1; i < static_cast<int>(q.size()); ++i) {
vs = q[i-1]; ve = q[i];
if(g[vs][ve] && Min > g[vs][ve]) {
Min = g[vs][ve];
p = vs;
}
}
sum += Min;
for(i = 1; i < static_cast<int>(q.size()); ++i) {
vs = q[i-1]; ve = q[i];
if(g[vs][ve]) {
g[vs][ve] -= Min;
g[ve][vs] += Min;
}
}
while(!q.empty() && q.back() != p) {
vis[q.back()] = false;
q.pop_back();
}
}
}
}
return sum;
}

int main() {
//freopen("data.in", "r", stdin);

int n, np, nc, m, x, y, z;
char t;
while(~scanf("%d%d%d%d", &n, &np, &nc, &m)) {
S = 0; T = n + 1;
memset(g, 0, sizeof(g));
while(m--) {
cin >> t >> x >> t >> y >> t >> z;
//printf("%d %d %d\n", x, y, z);
g[x + 1][y + 1] = z;
}
while(np--) {
cin >> t >> x >> t >> z;
//printf("%d %d\n", x, z);
g[S][x + 1] = z;
}
while(nc--) {
cin >> t >> x >> t >> z;
//printf("%d %d %d\n", x + 1, T, z);
g[x + 1][T] = z;
}
/*for(int i = 0; i <= T; ++i) {
for(int j = 0; j <= T; ++j) {
printf("%d ", g[i][j]);
}
cout << endl;
}
*/
printf("%d\n", Dinic());
}
return 0;
}






原文地址:https://www.cnblogs.com/vongang/p/2375494.html