HDU 3018 Ant Trip(一笔画问题)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3018
题意:每条边过且只过一次,问至少要画几笔才能全部边都经过。。孤立的点忽视。
分析:首先,你用笔来画的话,只可能有2种,一:每回路,a——>b 二:形成回路,a——>...——>a
对于图中的每一块,度数数为奇数的点必须是由第一种画出来的,所以奇数/2就是画的笔数
由两种结合而成的图,也只是奇数/2
特别的,如果图只有第二种的话,即该块中不存在奇数点,则只要画一笔
对于整副图(每一块块组合而成),等于 :第一块奇数点/2+第二块奇数点/2+.......,最后得,图的总奇数点/2
接着还要计算有多少块里不存在奇数点(不存在奇数点的那块中,一定没有第一种画法,只需要画一笔),累加起来就得到答案了。。。
代码:
#include <iostream> using namespace std; const int M = 100000 + 10; int gree[M]; int father[M]; int rank1[M]; int save[M]; bool used[M]; bool mark[M]; void Make_Set(int x) { father[x] = x; rank1[x] = 0; } int Find(int x) { int k = 0; while (x != father[x]) { save[k++] = x; x = father[x]; } for (int j = 0; j < k; j++) { father[save[j]] = x; } return x; } void Union(int a, int b) { int x = Find(a); int y = Find(b); if (x == y) { return; } if (rank1[x] < rank1[y]) { father[x] = y; } else { father[y] = x; if (rank1[x] == rank1[y]) { rank1[x]++; } } } int main() { int n, m; while (~scanf("%d%d", &n, &m)) { memset(gree, 0, sizeof(gree)); memset(used, 0, sizeof(used)); memset(mark, 0, sizeof(mark)); while (m--) { int a, b; scanf("%d%d", &a, &b); if (!used[a]) { used[a] = 1; Make_Set(a); } if (!used[b]) { used[b] = 1; Make_Set(b); } gree[a]++; gree[b]++; Union(a, b); } int ans = 0; for (int i = 1; i <= n; i++) { if (used[i] && gree[i] % 2 == 1) { if (mark[Find(i)] == 0) { mark[Find(i)] = 1;//标记该块已经有奇数点了 } ans++;//计算总奇数点 } } ans /= 2; //累加,看有多少块没奇数点。。。mark[老大] == 0没有奇数点 for (int i = 1; i <= n; i++) { if (used[i] && father[i] == i && mark[i] == 0) { ans++; } } printf("%d\n", ans); } return 0; }
posted on 2012-08-26 14:31 [S*I]SImMon_WCG______* 阅读(1026) 评论(0) 编辑 收藏 举报