欧拉回路
.下面是判有没有欧拉路或欧拉回路的,用并查集来做,判断是否联通,注意欧拉回路包括欧拉路。
无向图:回路:所有点度都是偶数,路:起点终点是奇数
有向图:回路:所有点的入度等于出度,路:起点或终点,一个点入度比出度大一,一个点出度比入度大一。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxm = 1e3 + 5; int indeg[maxm], pa[maxm], ran[maxm], isin[maxm]; void make_set(int x){ pa[x] = x; ran[x] = 0; } int findx(int x) { int r = x, temp; while(pa[r] != r) r = pa[r]; while(x != r) { temp = pa[x]; pa[x] = r; x = temp; } return x; } void unio(int x, int y) { x = findx(x); y = findx(y); if(x == y)return ; if(ran[x] > ran[y]) { pa[y] = x; } else { pa[x] = y; if(ran[x] == ran[y]) { ran[y]++; } } } int n, m, x, y; int main() { while(~scanf("%d", &n)) { if(n == 0) break; scanf("%d", &m); memset(indeg, 0, sizeof(indeg)); // memset(outdeg, 0, sizeof(outdeg)); memset(isin, 0, sizeof(isin)); for(int i = 1; i <= n; i++) { make_set(i); } for(int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); unio(x, y); indeg[x]++; indeg[y]++; isin[x] = isin[y] = 1; } int num = 0; for(int i = 1; i <= n; i++) { if(isin[i] && findx(i) == i) num++; } if(num > 1) { printf("0\n"); continue; } int flag = 0; for(int i = 1; i <= n; i++) { if(isin[i] && indeg[i] % 2) { flag = 1; } } if(flag) printf("0\n"); else printf("1\n"); } return 0; }
//这种类型是看存不存在欧拉回路或者道路,大部分是并查集的知识。
题目:john's trip
https://vjudge.net/contest/280900#problem/G
Johnny 有了一台新车,他想去访问他所有的朋友(赤裸裸的炫耀?),他的朋友有很多,住在城市中的街道上,于是他就开始规划自己的路了,在这个城市中有很多街道,他想找一个路径,这个路径经过一个街道仅一次,但能访问完他所有的朋友,他从他父母家出发,并且回来时也必须在他父母家。
在这个城市中,一共有N(N < 1995)个街道,共有M(M <= 44)个转折点,转折点就是一个街道的两端,每条街道和转折点的编号都不同。如果在一个转折点有多种选择,他会优先选择街道编号比较小的。
让你帮忙写一个程序,找到这个路径,如果找不到就打印“Round trip does not exist.”,从 1 号转折点出发,最后必须回到 1 号转折点,经过每条街道仅一次,访问完他所有的朋友,街道是双向的,但是不能掉头。
//这个题目edge存的是出发点与道路的长度,用vis数组标记是否存过,按字典序的话因为本来就是0-len,所以就是字典序排的
//注意这个dfs是到底才开始回溯,所以是反的
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef pair<int, int> pii; const int maxm = 2000; int deg[50], isin[50], edge[50][maxm]; int road[maxm], len, vis[maxm]; int now; //void make_set(int x){ // pa[x] = x; //} //int findx(int x) { //if (x != pa[x]) { //pa[x] = findx(pa[x]); //} //return pa[x]; //} // //void unio(int x, int y) { //x = findx(x); //y = findx(y); //if(x == y)return ; //pa[x] = y; //} void dfs(int x) { int i; for(i = 1; i <= len;i++) {
//i是指街道的编号。 if(edge[x][i] && !vis[i]){ // printf("%d\n", i); vis[i] = 1; dfs(edge[x][i]); road[++now] = i; } // printf("%d\n", i); } } int x, y, t, home; int main() { while(~scanf("%d%d", &x, &y)) { if(x == 0 && y == 0) break; len = -1; home = min(x, y); // for(int i = 1; i < maxm; i++) { // make_set(i); // } memset(deg, 0, sizeof(deg)); memset(isin, 0, sizeof(isin)); memset(edge, 0, sizeof(edge)); memset(vis, 0, sizeof(vis)); while(x != 0 && y != 0) { scanf("%d", &t); len = max(len, t); deg[x]++; deg[y]++; isin[x] = isin[y] = 1; // edge[x][t] += y; // edge[y][t] += x; edge[x][t] = y; edge[y][t] = x; scanf("%d%d", &x, &y); } int flag = 0; for(int i = 1; i <= 48; i++) { if(isin[i] && deg[i] % 2) { flag = 1; break; } } if(flag) { printf("Round trip does not exist.\n"); continue; } now = 0; dfs(home); // sort(road + 1, road + now + 1); for(int i = now; i > 0; i--) { if(i == now) printf("%d", road[i]); else printf(" %d", road[i]); } printf("\n"); } return 0; }
https://vjudge.net/contest/280900#problem/P
The necklace
这个题目和上面那个差不多。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef pair<int, int> pii; const int maxm = 55; int pa[maxm], deg[maxm], isin[maxm], edge[maxm][maxm]; pii road[1005]; int now; void make_set(int x){ pa[x] = x; } int findx(int x) { if (x != pa[x]) { pa[x] = findx(pa[x]); } return pa[x]; } void unio(int x, int y) { x = findx(x); y = findx(y); if(x == y)return ; pa[x] = y; } void dfs(int x) { int i; for(i = 1; i <= 50;i++) { if(edge[x][i]){ // printf("%d\n", i); edge[x][i]--; edge[i][x]--; dfs(i); road[now++] = make_pair(x, i);
//这个题目是要打印每条路的两个端点。 } // printf("%d\n", i); } } int t, n, x, y; int main() { scanf("%d", &t); int index = 0; while(t--) { scanf("%d", &n); int home; for(int i = 1; i <= 50; i++) { make_set(i); } memset(deg, 0, sizeof(deg)); memset(isin, 0, sizeof(isin)); memset(edge, 0, sizeof(edge)); while(n--) { scanf("%d%d", &x, &y); unio(x, y); home = x; deg[x]++; deg[y]++; edge[x][y]++; edge[y][x]++; isin[x] = isin[y] = 1; } int ant = 0; // printf("%d\n", ant); for(int i = 1; i <= 50; i++) { if(isin[i] && findx(i) == i) { ant++; } } if(ant > 1) { printf("Case #%d\n", ++index); printf("some beads may be lost\n\n"); continue; } int flag = 0; for(int i = 1; i <= 50; i++) { if(isin[i] && deg[i] % 2 != 0) { flag = 1; break; } } if(flag) { printf("Case #%d\n", ++index); printf("some beads may be lost\n\n"); } else { now = 1; dfs(home); printf("Case #%d\n", ++index); for(int i = now - 1; i > 0; i--) { printf("%d %d\n", road[i].first, road[i].second); } printf("\n"); } } return 0; }