靠二进制画几何[图论]

@Kaike

今天来浅谈一下图,听说自己写总结的人grade++,rp++。

像我这样可爱的人怎么能错过这个机会呢嘤嘤嘤。

毕竟图至少啃了15day++。

恩曾经的小弱渣从来都是仰望高端玩家虐图论

听说noip上一年考两道大图(つд⊂)而小弱渣还没学到

吓得本宝宝虎躯一震!!

恩废话不多说,来开正文。

 

2019/01/27:

时隔两年重新看这篇博客,又更新的好多东西,希望自己一直能不断进步把,而不是一直啃以前的东西QAQ

-------------------我是萌哒哒的分割线--------------------

刚开始先学图的储存。

 

  1. 邻接矩阵

邻接矩阵就是跟二维数组长得一毛(mu)一样奇奇怪怪的东xi

 1 #include<iostream>
 2 using namespace std;
 3 int n,a[100][100];
 4 int main()
 5 {
 6     cin>>n;
 7     //直接给出邻接矩阵,直接读。
 8     for(int i=1;i<=n;i++)
 9         for(int j=1;j<=n;j++)
10             cin>>a[i][j];
11     //给出两个顶点和权值
12     for(int i=1;i<=n;i++)
13     {
14         int xx,yy,vv;
15         cin>>xx>>yy>>vv;
16         a[xx][yy]=vv;
17         //双向图时
18         a[yy][xx]=vv;
19     }
20     //给出每个顶点的临界点
21     for(int i=1;i<=n;i++)
22     {
23         int k;
24         cin>>k;
25         for(int j=1;j<=k;j++)
26         {
27             int x;
28             cin>>x;
29             a[i][x]=1;
30             a[x][i]=1;
31         }
32     }
33     return 0;
34 }
邻接矩阵

 

2.邻接表

第一次看这玩意的时候内心万般草泥马奔过。

这TM都是什么玩意

后来经过滑稽大师cdc柴大叔的指导下,莫名其妙知道了些什么

然而教材太过简单,时常还会有些错的

小弱渣花了一整节自习课照着书上画了一幅图,发现!原来!跟书上一毛(mu)一样。本宝宝不开心,哦是十分不开心。

这大概是这个样子的

 1 #include<iostream>
 2 using namespace std;
 3 int n;
 4 int link[10010],len=0;
 5 struct ha
 6 {
 7     int y,v,next;
 8 }e[10010];
 9 void insert(int xx,int yy,int vv)
10 {
11     e[++len].next=link[xx];
12     link[xx]=len;
13     e[len].y=yy;
14     e[len].v=vv;
15 }
16 int main()
17 {
18     cin>>n;
19     int xx,yy,vv;
20     for(int i=1;i<=n;i++)
21     {
22         cin>>xx>>yy>>vv;
23         insert(xx,yy,vv);
24         insert(yy,xx,vv);
25     }
26     return 0;
27 }
邻接表

如果出现重边!邻接矩阵必须判断!!

 

-----------------我是萌萌哒的分割线------------------

 

DFS:以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;当没有未访问过的顶点时,则回到上一个顶点,继续试探访问别的顶点,直到所有的顶点都被访问过。

 1 #include<iostream>
 2 using namespace std;
 3 bool book[10010];//记录顶点是否被访问过
 4 int a[10010][10010],n,m;
 5 int inf=0x7fffffff;
 6 int sum=0;
 7 //邻接矩阵
 8 void dfs(int x)
 9 {
10     for(int i=1;i<=n;i++)
11         if(book[i]==0 && a[x][i])
12         {
13             book[i]=1;
14             dfs(i);
15         }
16 }
17 //邻接表
18 void dfs(int x)
19 {
20     for(int i=link[x];i;i=e[i].next)
21         if(book[e[i].y]==0)
22         {
23             book[e[i].y]=1;
24             dfs(e[i].y);
25         }
26 }
27 int main()
28 {
29     cin>>n;
30     //初始化
31     for(int i=1;i<=n;i++)
32         for(int j=1;j<=n;j++)
33             if(i==j)    a[i][j]=0;
34             else    a[i][j]=inf;
35     int xx,yy,vv;
36     for(int i=1;i<=m;i++)
37     {
38         cin>>xx>>yy>>vv;
39         a[xx][yy]=vv;
40         a[yy][xx]=vv;
41     }
42     for(int i=1;i<=n;i++)
43         if(book[i]==0)
44         {
45             //求无向图的连接分量
46             sum++;
47             dfs(i);
48         }
49     return 0;
50 }
dfs

 

BFS:以一个未被访问过的顶点作为起始顶点,访问其所有相邻的顶点,然后对每个相邻的顶点,在访问它们相邻的未被访问过的顶点,直到所有顶点都被访问过。

 1 #include<iostream>
 2 using namespace std;
 3 bool book[10010];//记录顶点是否被访问过
 4 int a[10010][10010],n,m;
 5 int inf=0x7fffffff;
 6 int sum=0;
 7 int q[10010];//队列,数组一定要开大!!
 8 //邻接矩阵
 9 void bfs(int x)
10 {
11     int head=0,tail=1;
12     q[1]=x;
13     book[i]=1;
14     while(head<tail)
15     {
16         int k=q[++head];
17         for(int i=1;i<=n;i++)
18             if(a[x][i] &&book[i]==0)
19             {
20                 q[++tail]=i;
21                 book[i]=1;
22             }
23     }
24 }
25 //邻接表
26 void dfs(int x)
27 {
28     int head=0,tail=1;
29     q[1]=x;
30     while(head<tail)
31     {
32         for(int i=link[q[head]];i;i=e[i].next)
33             if(book[e[i].y]==0)
34             {
35                 book[e[i].y]=1;
36                 q[++tail]=e[i].y;
37             }
38     }
39 }
40 int main()
41 {
42     cin>>n;
43     //初始化
44     for(int i=1;i<=n;i++)
45         for(int j=1;j<=n;j++)
46             if(i==j)    a[i][j]=0;
47             else    a[i][j]=inf;
48     int xx,yy,vv;
49     for(int i=1;i<=m;i++)
50     {
51         cin>>xx>>yy>>vv;
52         a[xx][yy]=vv;
53         a[yy][xx]=vv;
54     }
55     for(int i=1;i<=n;i++)
56         if(book[i]==0)
57         {
58             //求无向图的连接分量
59             sum++;
60             dfs(i);
61         }
62     return 0;
63 }
bfs

 

Bicoloring

传送门

这道题就是用bfs遍历一遍,用两种颜色来填充顶点,有边相邻的顶点颜色不能一样,邻接矩阵很好写,很好判断两个点,可是空间太大了。

邻接表想了好久,最终确定了两个顶点分别是 q[head] 和 e[i].y  i=Link[q[head]] 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<algorithm>
 8 #include<cmath>
 9 using namespace std;
10 typedef long long ll;
11 const int N = 200 + 20;
12 int a[N][N];
13 int cor[N];
14 int n, m,flag=1,xx,yy;
15 void dfs(int x)
16 {
17     for (int i = 0; i < n; i++)
18     {
19         if (a[x][i] && cor[i] == 0)
20         {
21             if (cor[x] == 1)
22                 cor[i] = 2;
23             else cor[i] = 1;
24             dfs(i);
25         }
26         else if (cor[i] == cor[x] &&a[x][i])
27         {
28             flag = 0;
29             return;
30         }
31     }
32 }
33 int main()
34 {
35     while (scanf("%d", &n))
36     {
37         if (n == 0)    break;
38         memset(a, 0, sizeof(a));
39         memset(cor, 0, sizeof(cor));
40         flag = 1;
41         scanf("%d",&m);
42         while (m--)
43         {
44             scanf("%d %d",&xx,&yy);
45             a[xx][yy] = 1;
46             a[yy][xx] = 1;
47         }
48         cor[0] = 1;
49         dfs(0);
50         if (flag == 0)    printf("NOT BICOLORABLE.\n");
51         else printf("BICOLORABLE.\n");
52     }
53 
54     return 0;
55 }
邻接矩阵的二分图
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<algorithm>
 9 #include<cmath>
10 using namespace std;
11 typedef long long ll;
12 const int N = 100000 + 20;
13 int Link[N],cor[N],len=0,bok[N];
14 int n, m;
15 int q[N];
16 struct student
17 {
18     int y, next;
19 }e[N];
20 void insert(int xx, int yy)
21 {
22     e[++len].next = Link[xx];
23     Link[xx] = len;
24     e[len].y = yy;
25 }
26 int bfs(int x)
27 {
28     int head = 1, tail = 2;
29     q[1] = x;
30     bok[x] = 1;
31     cor[x] = 1;
32     while (head < tail)
33     {
34         for (int i = Link[q[head]]; i; i = e[i].next)
35         {
36             if (cor[e[i].y] == 0)
37             {
38                 if (cor[q[head]] == 1)
39                     cor[e[i].y] = 2;
40                 else
41                     cor[e[i].y] = 1;
42             }
43             else if (cor[e[i].y] == cor[q[head]])
44                 return 0;
45             if (bok[e[i].y] == 0)
46             {
47                 bok[e[i].y] = 1;
48                 q[tail++] = e[i].y;
49             }
50         }
51         head++;
52     }
53     return 1;
54 }
55 int main()
56 {
57     while (scanf("%d", &n))
58     {
59         memset(bok, 0, sizeof(bok));
60         memset(Link, 0, sizeof(Link));
61         memset(q, 0, sizeof(q));
62         memset(cor, 0, sizeof(cor));
63         if (n == 0)    break;
64         scanf("%d", &m);
65         while (m--)
66         {
67             int xx, yy;
68             scanf("%d %d", &xx, &yy);
69             insert(xx, yy);
70             insert(yy, xx);
71         }
72         if (bfs(0))    printf("BICOLORABLE.\n");
73         else printf("NOT BICOLORABLE.\n");
74     }
75     return 0;
76 }
邻接表的二分图

 

拓扑排序:

拓扑就是类似于游戏中点技能,只有先把低级技能点了,才能点高阶技能。一个低阶技能可能对应多个高阶技能,高阶技能本身也可以互相对应。

那我们怎么办呢,另开一个数组indu,表示入度。

刚开始先找入度为0的点,从这个点开始遍历,然后再找,入度为1的点,再往下找入度为2的点。

每次找到一个,就减去它的入度,相当于把前面那个点删除掉,相应的边也删除掉。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<algorithm>
 9 #include<cmath>
10 using namespace std;
11 typedef long long ll;
12 const int N = 10000;
13 int Link[110], bok[110],len=0,indu[110],que[N];
14 int n, m, xx, yy;
15 struct student
16 {
17     int y, next;
18 }e[N];
19 void insert(int xx, int yy)
20 {
21     e[++len].next = Link[xx];
22     Link[xx] = len;
23     e[len].y = yy;
24 }
25 void bfs()
26 {
27     int head = 1, tail = 1;
28     for (int i = 1; i <= n; i++)
29         if (indu[i] == 0)
30         {
31             que[tail++] = i;
32             bok[i] = 1;
33         }
34     while (head < tail)
35     {
36         for (int i = Link[que[head]]; i; i = e[i].next)
37         {
38             if (--indu[e[i].y] == 0 && bok[e[i].y] == 0)
39             {
40                 que[tail++] = e[i].y;
41                 bok[e[i].y] = 1;
42             }
43         }
44         head++;
45     }
46     printf("%d",que[1]);
47     for (int i = 2; i <=n; i++)
48         printf(" %d",que[i]);
49     printf("\n");
50 }
51 int main()
52 {
53     while (scanf("%d %d",&n,&m))
54     {
55         if (n == 0)    break;
56         memset(e, 0, sizeof(e));
57         memset(Link, 0, sizeof(Link));
58         memset(que, 0, sizeof(que));
59         memset(bok, 0, sizeof(bok));
60         memset(indu, 0, sizeof(indu));
61         while (m--)
62         {
63             scanf("%d %d", &xx, &yy);
64             insert(xx, yy);
65             indu[yy]++;
66         }
67         bfs();
68     }
69     return 0;
70 }
邻接表的拓扑排序bfs

(他们全都用的stl的vector,我用的邻接表啊,高端东西,没有资料全靠自己创。好难过。)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 #define ll long long
13 const int N = 12500 + 10;
14 priority_queue<int, vector<int>, greater<int> >q;
15 int Link[510], bok[510],a[510],len=0,indu[510],cnt=0;
16 int n, m, xx, yy;
17 int ans = 0;
18 struct student
19 {
20     int y, next;
21 }e[N];
22 void insert(int xx, int yy)
23 {
24     e[++len].next = Link[xx];
25     Link[xx] = len;
26     e[len].y = yy;
27 }
28 void bfs()
29 {
30     cnt = 0;
31     ans = 0;
32     for(int i=1;i<=n;i++)
33         if (indu[i] == 0)
34         {
35             bok[i] = 1;
36             q.push(i);
37             //cout << i << endl;
38         }
39     //cout << endl;
40     while (!q.empty())
41     {
42         //a[++cnt] = q.top();
43         int tt = q.top();
44         q.pop();
45         ans++;
46         if (ans == 1)
47             printf("%d",tt);
48         else printf(" %d",tt);
49         for (int i = Link[tt]; i; i = e[i].next)
50         {
51             if (--indu[e[i].y] == 0 && bok[e[i].y] == 0)
52             {
53                 q.push(e[i].y);
54                 bok[e[i].y] = 1;
55             }
56         }
57     }
58     printf("\n");
59 }
60 int main()
61 {
62     while (scanf("%d %d", &n, &m) != EOF)
63     {
64         memset(Link, 0, sizeof(Link));
65         memset(bok, 0, sizeof(bok));
66         memset(e, 0, sizeof(e));
67         memset(a, 0, sizeof(a));
68         memset(indu, 0, sizeof(indu));
69         len = 0;
70         while (m--)
71         {
72             scanf("%d %d",&xx,&yy);
73             indu[yy]++;
74             insert(xx, yy);
75         }
76         bfs();
77     }
78 
79     return 0;
80 }
优先队列的拓扑排序

 

举个例子如图:

如果你用优先队列拓扑排序得到的是:3 5 6 4 1 7 8 9 2 0

但是正确答案为 6 4 1 3 9 2 5 7 8 0 这样使得小的(1)尽量在前面。

优先队列是让数字整体小的在前面,而编号最小是让1尽量在前面,这两者是不同的,想了好久才知道QAQ。

 1 #include "pch.h"
 2 #pragma warning(disable:4996)
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<string>
 6 #include<cstring>
 7 #include<map>
 8 #include<set>
 9 #include<vector>
10 #include<queue>
11 #include<algorithm>
12 #include<cmath>
13 using namespace std;
14 #define ll long long
15 const int N = 100000 + 10;
16 priority_queue<int, vector<int>, less<int> >q;
17 int Link[30010], bok[30010],a[30010],len=0,indu[30010],cnt=0;
18 int n, m, xx, yy;
19 int ans = 0;
20 struct student
21 {
22     int y, next;
23 }e[N];
24 void insert(int xx, int yy)
25 {
26     e[++len].next = Link[xx];
27     Link[xx] = len;
28     e[len].y = yy;
29 }
30 void bfs()
31 {
32     cnt = 0;
33     ans = 0;
34     for(int i=1;i<=n;i++)
35         if (indu[i] == 0)
36         {
37             bok[i] = 1;
38             q.push(i);
39             //cout << i << endl;
40         }
41     //cout << endl;
42     while (!q.empty())
43     {
44         //a[++cnt] = q.top();
45         int tt = q.top();
46         q.pop();
47         a[++ans] = tt;
48         for (int i = Link[tt]; i; i = e[i].next)
49         {
50             if (--indu[e[i].y] == 0 && bok[e[i].y] == 0)
51             {
52                 q.push(e[i].y);
53                 bok[e[i].y] = 1;
54             }
55         }
56     }
57     for (int i = ans; i >= 1; i--)
58     {
59         if (i == ans)
60             printf("%d",a[i]);
61         else printf(" %d",a[i]);
62     }
63     printf("\n");
64 }
65 int main()
66 {
67     int t;
68     scanf("%d",&t);
69     while (t--)
70     {
71         scanf("%d %d", &n, &m);
72         memset(Link, 0, sizeof(Link));
73         memset(bok, 0, sizeof(bok));
74         memset(e, 0, sizeof(e));
75         memset(a, 0, sizeof(a));
76         memset(indu, 0, sizeof(indu));
77         len = 0;
78         while (m--)
79         {
80             scanf("%d %d",&xx,&yy);
81             indu[xx]++;
82             insert(yy, xx);
83         }
84         bfs();
85     }
86 
87     return 0;
88 }
编号最小反向建图的拓扑排序

还搞了搞优先队列

1 priority_queue <int,vector<int>,greater<int> > q;
2 priority_queue <int,vector<int>,less<int> >q;

 

欧拉回路:

欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?

如何判断欧拉回路呢:首先它是连通图,其次对于无向图来说,所有顶点度数为偶数。

判断联通可以用并查集,判断度数很好写。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 #define ll long long
13 const int N = 1010;
14 int a[N][N],indu[N],par[N];
15 int n, m, xx, yy;
16 int find(int x)
17 {
18     if (par[x] == x)    return x;
19     return par[x] = find(par[x]);
20 }
21 void hebing(int a, int b)
22 {
23     a = find(a);
24     b = find(b);
25     if (a != b)
26         par[a] = b;
27 }
28 int main()
29 {
30     while (scanf("%d", &n))
31     {
32         if (n == 0)    break;
33         scanf("%d", &m);
34         memset(a, 0, sizeof(a));
35         memset(indu, 0, sizeof(indu));
36         for (int i = 1; i <= n; i++)
37             par[i] = i;
38         while (m--)
39         {
40             scanf("%d %d", &xx, &yy);
41             indu[xx]++;
42             indu[yy]++;
43             hebing(xx, yy);
44         }
45         int cnt = 0;
46         for (int i = 1; i <= n; i++)
47             if (par[i] == i)
48                 cnt++;
49         if (cnt > 1)
50         {
51             printf("0\n");
52             continue;
53         }
54         cnt = 0;
55         for (int i = 1; i <= n; i++)
56             if (indu[i] % 2 == 1)
57                 cnt++;
58         if (cnt > 0)
59             printf("0\n");
60         else printf("1\n");
61     }
62 
63     return 0;
64 }
判断欧拉回路

 

输出欧拉回路:

就是从一个顶点起,一笔走过所有的边。dfs遍历边!

以前的dfs和bfs都是遍历顶点,而这个是遍历边!

这个只能用dfs,我想了想因为你一笔走的就是一个dfs的过程,不存在bfs的过程,如果有bfs的话,那就画一条回去,在画另一条。跟题意不否。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 #define ll long long
13 const int N =10010;
14 const int M = 50000 + 100;
15 int Link[N],bok[N],len=0,q[N];
16 int n, m, xx, yy;
17 struct student
18 {
19     int y, next,vis;
20 }e[M*2];
21 void insert(int xx, int yy)
22 {
23     e[++len].next = Link[xx];
24     Link[xx] = len;
25     e[len].y = yy;
26     e[len].vis = 0;
27 }
28 void init()
29 {
30     scanf("%d %d",&n,&m);
31     while (m--)
32     {
33         scanf("%d %d",&xx,&yy);
34         insert(xx, yy);
35         insert(yy, xx);
36     }
37 }
38 void dfs(int x)
39 {
40     for(int i=Link[x];i;i=e[i].next)
41         if (e[i].vis == 0)
42         {
43             e[i].vis = 1;
44             dfs(e[i].y);
45         }
46     printf("%d\n",x);
47 }
48 int main()
49 {
50     init();
51     dfs(1);
52     return 0;
53 }
输出欧拉回路dfs

 

判断欧拉回路的个数:

传送门

对于每个以i为根的连通分量我们记录属于该连通分量的点数目num[i]和该连通分量中奇度点的个数odd[i].
如果num[i]==0或1,需0笔.(注意num[i]==0表示i点不是根,num[i]==1表示i点是一个孤立的点.)
如果num[i]>1且odd[i]==0 需1笔
如果num[i]>1且odd[i]>0 需odd[i]/2笔

 

1205.田野上的环

传送门

刚开始的时候小弱渣刚刚理解什么是邻接矩阵,对于dfs还不熟

然而现在看书上 邻接矩阵+dfs 简直扯淡

总而言之这道题就是找与1不相连的点

dfs 两个变量 用(1,i)来遍历;

找与1相连,然后依次递归

最后看谁还没有遍历,按顺序输出

最后用布尔判断 是不是没有!

 

 1 #include<iostream>
 2 using namespace std;
 3 int a[300][300],n,m,x,y;
 4 bool b=0,f[300];
 5 void dfs(int x,int y)
 6 {
 7     if(a[x][y]==1&&f[y]!=1)
 8     {
 9         f[y]=1;
10         for(int i=1;i<=n;i++)
11             dfs(y,i);
12     }
13     else    return;
14 }
15 int main()
16 {
17     cin>>n>>m;
18     for(int i=1;i<=m;i++)
19     {
20         cin>>x>>y;
21         a[x][y]=1;
22         a[y][x]=1;
23     }
24     for(int i=1;i<=n;i++)
25         a[i][i]=1;
26     for(int i=2;i<=n;i++)
27         dfs(1,i);
28     for(int i=2;i<=n;i++)
29         if(f[i]==0)
30         {   b=1;
31             cout<<i<<endl;
32         }
33     if(b==0)    cout<<0<<endl;
34     return 0;
35 }
1205

 

 

1206.1207.1208.犯罪集团

传送门

就是找几个连通分量,注意数组开大,小弱渣卡了好几次。

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int n,m,x,y,len=0;
 5 int link[50100],ans=0,q[50100];
 6 bool f[50100];
 7 struct edge
 8 {
 9     int y,next;
10 }e[50100];
11 void in(int xx,int yy)
12 {
13     e[++len].next=link[xx];
14     link[xx]=len;
15     e[len].y=yy;
16 }
17 void bfs(int k)
18 {
19     memset(q,0,sizeof(q));
20     int head=0,tail=1;
21     q[1]=k;
22     while(head++<tail)
23         for(int i=link[q[head]];i;i=e[i].next)
24             if(!f[e[i].y])
25             {
26                 f[e[i].y]=1;
27                 q[++tail]=e[i].y;
28             }
29 }
30 int main()
31 {
32     cin>>n>>m;
33     for(int i=1;i<=m;i++)
34     {
35         cin>>x>>y;
36         in(x,y);
37         in(y,x);
38     }
39     for(int i=1;i<=n;i++)
40         if(!f[i])
41         {
42             ans++;
43             bfs(i);
44         }
45     cout<<ans<<endl;
46     return 0;
47 }
1208

 

1210.骑马修栅栏

传送门

书上写着欧拉路与欧拉回路,把求最小路都做出来了死活还都不知道欧拉路是什么鬼

嗯去科技馆的时候好像看过一个叫欧拉路的玩意

然而跟题目有毛关系(怒拍桌子!)

啊因为不会欧拉路,so现在看这道题还是不会

你看这个人怎么这么懒。没办法你来打我啊

算了我们还是跳过这道题吧

 

 1 /*
 2 by kaike
 3 11/15/2016
 4 */
 5 //这题是让求出一条欧拉路。
 6 #include<iostream>
 7 using namespace std;
 8 int xx,yy,m;
 9 int l[1028][1028],du[1028],maxx=0;
10 int a[1028],t=0;
11 //找到和它相连的,依次删除他们之间的连线。
12 //再找新的点,最后把这个点加入输出队列。
13 void find(int k)
14 {
15     for(int i=1;i<=maxx;i++)
16         if(l[k][i])
17         {
18             l[k][i]--;
19             l[i][k]--;
20             find(i);
21         }
22     a[++t]=k;
23 }
24 int main()
25 {
26     cin>>m;
27     for(int i=1;i<=m;i++)
28     {
29         cin>>xx>>yy;
30         l[xx][yy]++;    
31         l[yy][xx]++;
32         du[xx]++;
33         du[yy]++;
34         if(xx>maxx) maxx=xx;
35         if(yy>maxx) maxx=yy;
36     }
37     int s=1;
38 //数据保证至少有1个解,那就一定存在欧拉路。
39 //我们要选一个点为起点,要在字典序中找出最小的,就要找最小的点为起点。
40     for(int i=1;i<=maxx;i++)
41         if(du[i]%2==1)
42         {
43             s=i;
44             break;
45         }
46 //对于当前的点,把所有点从小到大搜索。
47     find(s);
48 //这样做之后,顺序是反着的。
49     for(int i=m+1;i>0;i--)
50         cout<<a[i]<<endl;
51     return 0;
52 }
1210

 

 

1209.几何图形还原

传送门

这道题需要多注意!多注意!多注意!

因为还需要回溯啊

Why?

害怕这条路走不通,换一条路试试咯

所有的边都连起来了,就说明最后一个顶点跟1顶点肯定是连起来的

因为要输出字典序最小的那个,所以只要从1开始遍历就哦可,算是个隐藏的小细节

dfs 每遍历一个点就用数组记录下来,然后继续遍历

回溯。

最后判断最后一个点跟1是否相连,相连输出退出。

 1 #include<iostream>
 2 #include<stdlib.h>
 3 using namespace std;
 4 int n,ans[60],t=1;
 5 int a[60][60],xx,yy;
 6 int f[60];
 7 bool book[60];
 8 void dfs(int k)
 9 {
10     if(t==n)
11     {
12         if(f[ans[t]]!=1)    return;
13         else
14         {    for(int i=1;i<=n;i++)
15                 cout<<ans[i]<<' ';
16             exit(0);
17         }
18     }
19     for(int i=1;i<=n;i++)
20         if(a[k][i]==1&& book[i]==0)
21         {
22             book[i]=1;
23             ans[++t]=i;
24             dfs(i);
25             book[i]=0;
26             t--;
27         }
28 }
29 int main()
30 {
31     cin>>n;
32     while(cin>>xx>>yy)
33     {
34         a[xx][yy]=1;
35         a[yy][xx]=1;
36     }
37     for(int i=1;i<=n;i++)
38         f[i]=a[i][1];
39     book[1]=1;
40     ans[1]=1;
41     dfs(1);
42     return 0;
43 }
1209

 

1211.街道赛跑

传送门

题太复杂,看题解都看不懂,回来写。

这里这里

--------------------我是萌萌哒的分割线---------------

 

嗯真开心,终于要到最短路了。

累了本宝宝了。

 

1212. Geodetic集合

传送门

这应该是一个求最短路的吧,然而教材上写图的传递闭包,什么鬼

就是求从 i-j 最短路中可能经过的点 顺序输出。

要多注意!多注意!多注意!

先用 floyed 求出每个点的最短路

然后依次枚举,如果最短路相同 用三维数组存起来点

然后输出

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 int a[50][50],b[50][50][50],c[50][50];
 5 int n,m,q;
 6 int main()
 7 {
 8     cin>>n>>m;
 9     for(int i=1;i<=n;i++)
10         for(int j=1;j<=n;j++)
11             if(i==j)    a[i][j]=0;
12             else    a[i][j]=100;
13     int xx,yy;
14     for(int i=1;i<=m;i++)
15     {
16         cin>>xx>>yy;
17         a[xx][yy]=1;
18         a[yy][xx]=1;
19     }
20     for(int k=1;k<=n;k++)
21         for(int i=1;i<=n;i++)
22             for(int j=1;j<=n;j++)
23                 if(a[i][j]>a[i][k]+a[k][j])
24                     a[i][j]=a[i][k]+a[k][j];
25     for(int k=1;k<=n;k++)
26         for(int i=1;i<=n;i++)
27             for(int j=1;j<=n;j++)
28                 if(a[i][j]==a[i][k]+a[k][j] && k!=i && k!=j && i!=j )
29                     b[i][j][c[i][j]++]=k;
30     cin>>q;
31     int x,y;
32     for(int i=1;i<=q;i++)
33     {
34         cin>>x>>y;
35         b[x][y][c[x][y]++]=x;
36         b[x][y][c[x][y]++]=y;
37         sort(b[x][y],b[x][y]+c[x][y]+1);
38         for(int j=1;j<=c[x][y];j++)
39             cout<<b[x][y][j]<<' ';
40         cout<<endl;
41     }
42     return 0;
43 }
1212

 

FLOYED

就是找中间点看是否可以松弛,适用于连接矩阵。

1 for(int k=1;k<=n;k++)
2     for(int i=1;i<=n;i++)
3         for(int j=1;j<=n;j++)
4             if(a[i][j]>a[i][k]+a[k][j])
5                 a[i][j]=a[i][k]+a[k][j];
floyed

 

1213.最优乘车

传送门

直接floyed 然后输出 a[1][n]-1

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int a[510][510],n,m,t[510],l;
 5 char c;
 6 int main()
 7 {
 8     cin>>m>>n;
 9     for(int i=1;i<=n;i++)
10         for(int j=1;j<=n;j++)
11             if(i==j)    a[i][j]=0;
12             else    a[i][j]=1000;
13     for(int i=1;i<=m;i++)
14     {
15         c=' ';
16         l=0;
17         while(c!=10)
18         {
19             cin>>t[++l];
20             c=getchar();
21         }
22         for(int j=1;j<l;j++)
23             for(int k=j+1;k<=l;k++)
24                 a[t[j]][t[k]]=1;
25     }
26     for(int k=1;k<=n;k++)
27         for(int i=1;i<=n;i++)
28             for(int j=1;j<=n;j++)
29                 if(a[i][j]>a[i][k]+a[k][j])
30                     a[i][j]=a[i][k]+a[k][j];
31     if((a[1][n]==1000)||(a[1][n]==0))  cout<<"NO"<<endl;
32     else    cout<<a[1][n]-1<<endl;
33     return 0;
34 }
1213

 

1214. Bessie Come Home

传送门

这道题最大的坑点就是有a-Z 个粮仓

然后把字符转换为数字,floyed

从大写字母中找去粮仓最小的路程 输出,并输出 i;

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<string.h>
 4 #define MAX 0xfffffff
 5 using namespace std;
 6 int p,m[55][55],w[55],t,minnum=MAX;
 7 char t1,t2,ans;
 8 char ch(char t)
 9 {
10     if(isupper(t))
11     {
12         t=t-'A'+26;
13         w[t]=1;
14         return t;
15     }
16     return t-'a';
17 }
18 int main(void)
19 {
20     cin>>p;
21     memset(m,-1,sizeof(m));
22     for(int i=0;i<52;i++)
23         m[i][i]=0; 
24     for(int i=0;i<p;i++)
25     {
26         cin>>t1>>t2>>t;
27         t1=ch(t1);
28         t2=ch(t2);
29         if(m[t1][t2]==-1 || m[t1][t2]>t)
30         {
31             m[t1][t2]=t;
32             m[t2][t1]=t;
33         }
34     }
35     for(int i=0;i<55;i++)
36         for(int j=0;j<55;j++)
37             for(int k=0;k<55;k++)
38                 if(m[i][k]!=-1 && m[j][k]!=-1)
39                     if(m[i][j]==-1 || (m[j][k]+m[i][k]<m[i][j]))
40                         m[i][j]=m[j][k]+m[i][k];
41     for(int i=26;i<51;i++)
42         if(w[i] && m[i][51]<minnum)
43         {
44             minnum=m[i][51];
45             ans=(char)(i-26+'A');
46         }
47     cout<<ans<<' '<<minnum<<endl;
48     return 0;
49 }
1214

 

DIJKSTRA

这是求指定一个点到其余各个顶点的最短路径

(单源 非负)

用book 数组标记

用 dis 数组标记距离

找出离 1 最近的点,然后依次松弛 floyed

 1 #include<iostream>
 2 using namespace std;
 3 int a[10010][10010],dis[10010];
 4 bool book[10010];
 5 int inf=0x7fffffff;
 6 int minn=inf;
 7 int main()
 8 {
 9     int n,m;
10     cin>>n>>m;
11     for(int i=1;i<=n;i++)
12         for(int j=1;j<=n;j++)
13             if(i==j)    a[i][j]=0;
14             else    a[i][j]=inf;
15     int xx,yy,vv;
16     for(int i=1;i<=m;i++)
17     {
18         cin>>xx>>yy>>vv;
19         a[xx][yy]=vv;
20         //a[yy][xx]=vv;
21     }
22     for(int i=1;i<=n;i++)
23     {   dis[i]=a[1][i];
24         book[i]=0;
25     }
26     book[1]=1;
27     int u;
28     //dijkstra
29     for(int i=1;i<=n;i++)
30     {
31         minn=inf;
32         for(int j=1;j<=n;j++)
33             if(book[j]==0 && dis[j]<minn )
34             {
35                 minn=dis[j];
36                 u=j;
37             }
38         book[u]=1;
39         for(int j=1;j<=n;j++)
40             if(a[u][j]<inf)
41                 if(dis[j]>dis[u]+a[u][j])
42                     dis[j]=dis[u]+a[u][j];
43     }
44     for(int i=1;i<=n;i++)
45         cout<<dis[i]<<endl;
46     return 0;
47 }
dijkstra

邻接表:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 typedef long long ll;
13 const int inf=0x7fffffff;
14 const int N=200+10;
15 const int M=20000;
16 int n,m,xx,yy,vv;
17 int Link[N],len=0,bok[N],dis[N];
18 struct student
19 {
20     int y,v,next;
21 }e[M];
22 void insert(int xx,int yy,int vv)
23 {
24     e[++len].next=Link[xx];
25     Link[xx]=len;
26     e[len].y=yy;
27     e[len].v=vv;
28 }
29 void init()
30 {
31     scanf("%d %d",&n,&m);
32     while(m--)
33     {
34         scanf("%d %d %d",&xx,&yy,&vv);
35         insert(xx,yy,vv);
36     }
37 }
38 void print()
39 {
40     for(int i=1;i<=n;i++)
41         printf("%d ",dis[i]);
42     printf("\n");
43 }
44 void dijkstra()
45 {
46     bok[1]=1;
47     int u;
48     for(int i=2;i<=n;i++)
49         dis[i]=inf;
50     for(int i=Link[1];i;i=e[i].next)
51         dis[e[i].y]=e[i].v;
52     for(int i=1;i<n;i++)
53     {
54         int minn=inf;
55         for(int j=1;j<=n;j++)
56             if(bok[j]==0&&dis[j]<minn)
57             {
58                 minn=dis[j];
59                 u=j;
60             }
61         bok[u]=1;
62         for(int i=Link[u];i;i=e[i].next)
63         {
64             if(dis[e[i].y]>dis[u]+e[i].v)
65                 dis[e[i].y]=dis[u]+e[i].v;
66         }
67     }
68 }
69 int main()
70 {
71     init();
72     dijkstra();
73     print();
74     return 0;
75 }
View Code

DIJKSTRA:

1.找出最近的那个点

2.更新

 

1217.晚餐

传送门

就是dijkstra ,然后求距离小于 t 的有几个

 1 #include<iostream>
 2 using namespace std;
 3 int t,f,p,ans=0;
 4 int a[550][550],dis[550];
 5 bool book[550];
 6 int main()
 7 {
 8     cin>>t>>f>>p;
 9     for(int i=1;i<=f;i++)
10         for(int j=1;j<=f;j++)
11             if(i==j)    a[i][j]=0;
12             else    a[i][j]=9999999;
13     int xx,yy,vv;
14     for(int i=1;i<=p;i++)
15     {
16         cin>>xx>>yy>>vv;
17         if(xx!=yy)
18           if(a[xx][yy]>vv)    
19              { a[xx][yy]=vv;     a[yy][xx]=vv;}
20     }
21     for(int i=1;i<=f;i++)
22     {    dis[i]=a[1][i];
23         book[i]=0;
24     }
25     book[1]=1;
26     for(int i=1;i<f;i++)
27     {
28         int u=1;
29         int min=9999999;
30         for(int j=1;j<=f;j++)
31             if(min>dis[j] && book[j]==0)
32             {
33                 min=dis[j];
34                 u=j;
35             }
36         book[u]=1;
37         for(int v=1;v<=f;v++)
38             if(a[u][v]<9999999)
39                 if(dis[v]>dis[u]+a[u][v])
40                     dis[v]=dis[u]+a[u][v];
41     }
42     for(int i=1;i<=f;i++)
43         if(dis[i]<=t)    ans++;
44     cout<<ans<<endl;
45     return 0;
46 }
1217

 

BELLMAN-FORD

这个主要是判断负环

 1 #include<iostream>
 2 using namespace std;
 3 int n,m;
 4 int a[10010][10010],dis[10010];
 5 int x[10010],y[10010],v[10010];
 6 int main()
 7 {
 8     cin>>n>>m;
 9     int xx,yy,vv;
10     for(int i=1;i<=m;i++)
11         cin>>x[i]>>y[i]>>v[i];
12     for(int i=1;i<=n;i++)
13         dis[i]=0x7fffffff;
14     dis[1]=0;
15     for(int k=1;k<n;k++)
16         for(int i=1;i<=m;i++)
17             if(dis[y[i]]>dis[x[i]]+v[i])
18                 dis[y[i]]=dis[x[i]]+v[i];
19     for(int i=1;i<=n;i++)
20         cout<<dis[i]<<endl;
21     return 0;
22 }
bellman-ford

 

SPFA

就是bellman-ford 的队列 用邻接表

 

 1 /*
 2 by kaike
 3 11/16/2016
 4 */
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 const int MAXN=10010;
 9 int que[MAXN],dis[MAXN],bok[MAXN],Link[MAXN],len=0,head=0,tail=1;
10 int m,n,x,y,v;
11 struct qaq
12 {
13     int next,y,v;
14 }e[MAXN];
15 void insert(int xx,int yy,int vv)
16 {
17     e[++len].next=Link[xx];
18     Link[xx]=len;
19     e[len].y=yy;
20     e[lrn].v=vv;
21 }
22 void init()
23 {
24     cin>>n>>m;
25     for(int i=1;i<=m;i++)
26     {    cin>>x>>y>>v;
27         insert(x,y,v);
28         insert(y,x,v);
29     }
30 }
31 void spfa()
32 {
33     dis[S]=0;
34     bok[S]=1;
35     que[1]=S;
36     head=0; tail=1;
37     while(head<tail)
38     {
39         int t=q[++head];
40         bok[t]=0;
41         for(int i=Link[t];i;i=e[i].next)
42         {
43             if(dis[e[i].y]>dis[t]+e[i].v)
44             {
45                 dis[e[i].y]=dis[t]+e[i].v;
46                 if(bok[e[i].y]==0)
47                 {
48                     que[++tail]=e[i].y;
49                     bok[e[i].y]=1;
50                 }
51             }
52         }
53     }
54 }
55 int main()
56 {
57     init();
58     spfa();
59     return 0;
60 }
我以后再也不学乱七八糟的算法了= =

 

具体看1216.虫洞

 

1216.虫洞

传送门

就是输入两组数据,一组双向,一组单项负环,用spfa 如果有负环,就说明可以,没有就不可以

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int f,n,m,w;
 5 int len=0;
 6 int link[510],dis[510];
 7 bool flag,book[510];
 8 struct data
 9 {
10     int y,v,next;
11 }e[100100];
12 void ins(int xx,int yy,int vv)
13 {
14     e[++len].next=link[xx];
15     link[xx]=len;
16     e[len].y=yy;
17     e[len].v=vv;
18 }
19 void spfa(int x)
20 {
21     book[x]=1;
22     for(int i=link[x];i;i=e[i].next)
23     {
24         if(e[i].v+dis[x]<dis[e[i].y])
25         {    if(book[e[i].y])    {
26                 flag=1;
27                 return ;
28             }
29             else
30             {
31                 dis[e[i].y]=e[i].v+dis[x];
32                 spfa(e[i].y);
33             }
34         }
35     }
36     book[x]=0;
37 }
38 bool judge()
39 {
40     for(int i=1;i<=n;i++)
41         dis[i]=book[i]=0;
42     flag=0;
43     for(int i=1;i<=n;i++)
44     {
45         spfa(i);
46         if(flag)    return 1;
47     }
48     return 0;
49 }
50 int main()
51 {
52     cin>>f;
53     while(f--)
54     {
55         len=0;
56         memset(link,0,sizeof(link));
57         cin>>n>>m>>w;
58         int xx,yy,vv;
59         for(int i=1;i<=m;i++)
60         {   
61             cin>>xx>>yy>>vv;
62             ins(xx,yy,vv);
63             ins(yy,xx,vv);
64         }
65         for(int i=1;i<=w;i++)
66         {
67             cin>>xx>>yy>>vv;
68             ins(xx,yy,-vv);
69         }
70         if(judge()) cout<<"YES"<<endl;
71         else    cout<<"NO"<<endl;
72     }
73     return 0;
74 }
1216

 如果进队次数>n 就说明有负环。可以用队列,反而dfs不知道怎么写。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 typedef long long ll;
13 const int inf=0x7fffffff;
14 const int N=500+10;
15 const int M=100100;
16 int T,n,m,w,xx,yy,vv;
17 int Link[N],len=0,bok[N],dis[N],upp[N],que[M];
18 struct student
19 {
20     int y,v,next;
21 }e[M];
22 void insert(int xx,int yy,int vv)
23 {
24     e[++len].next=Link[xx];
25     Link[xx]=len;
26     e[len].y=yy;
27     e[len].v=vv;
28 }
29 void init()
30 {
31     memset(e,0,sizeof(e));
32     memset(Link,0,sizeof(Link));
33     len=0;
34     scanf("%d %d %d",&n,&m,&w);
35     while(m--)
36     {
37         scanf("%d %d %d",&xx,&yy,&vv);
38         insert(xx,yy,vv);
39         insert(yy,xx,vv);
40     }
41     while(w--)
42     {
43         scanf("%d %d %d",&xx,&yy,&vv);
44         insert(xx,yy,-vv);
45     }
46 }
47 void print()
48 {
49     for(int i=1;i<=n;i++)
50         printf("%d ",dis[i]);
51     printf("\n");
52 }
53 int spfa()
54 {
55     memset(upp,0,sizeof(upp));
56     memset(bok,0,sizeof(bok));
57     memset(que,0,sizeof(que));
58     for(int i=1;i<=n;i++)
59         dis[i]=inf;
60     int head=1,tail=2;
61     dis[1]=0;
62     que[1]=1;
63     bok[1]=1;
64     while(head<tail)
65     {
66         int tt=que[head];
67         bok[tt]=0;
68         for(int i=Link[tt];i;i=e[i].next)
69         {
70             if(dis[e[i].y]>dis[tt]+e[i].v)
71             {
72                 dis[e[i].y]=dis[tt]+e[i].v;
73                 if(bok[e[i].y]==0)
74                 {
75                     que[tail++]=e[i].y;
76                     bok[e[i].y]=1;
77                     upp[e[i].y]++;
78                 }
79                 if(upp[e[i].y]>n)
80                         return 0;
81             }
82         }
83         head++;
84     }
85     return 1;
86 }
87 int main()
88 {
89     scanf("%d",&T);
90     while(T--)
91     {
92     init();
93     if(spfa())
94         printf("NO\n");
95     else printf("YES\n");
96     }
97     return 0;
98 }
View Code

(超时code)

1215.香甜的黄油

传送门

构建一个双向图

然后spfa 好像是第一个超时是因为没有 book 数组标记

然后记录所有需要的最小值

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int n,p,c;
 5 int a[850][850],b[510],dis[850],q[100100];
 6 int maxx=99999999,sum;
 7 void spfa(int x)
 8 {
 9     memset(dis,260,sizeof(dis));
10     int head=0,tail=1;
11     q[0]=x;
12     dis[x]=0;
13     while(head<tail)
14     {
15         for(int i=1;i<=p;i++)
16             if(dis[i]>a[q[head]][i]+dis[q[head]])
17             {
18                 q[tail++]=i;
19                 dis[i]=a[q[head]][i]+dis[q[head]];
20             }
21         head++;
22     }
23     sum=0;
24     for(int i=1;i<=n;i++)
25         sum+=dis[b[i]];
26 }
27 int main()
28 {
29     memset(a,260,sizeof(a));
30     cin>>n>>p>>c;
31     for(int i=1;i<=n;i++)
32         cin>>b[i];
33     int xx,yy,vv;
34     for(int i=1;i<=c;i++)
35     {
36         cin>>xx>>yy>>vv;
37         a[xx][yy]=a[yy][xx]=vv;
38     }
39     for(int i=1;i<=p;i++)
40     {
41         spfa(i);
42         if(maxx>sum)    maxx=sum;
43     }
44     cout<<maxx<<endl;
45     return 0;
46 }
1215(超时)
 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,p,c;
 6 bool book[1010];
 7 int len=0,ans=0x7fffffff;
 8 int b[850],q[100010],dis[1000],link[1000];
 9 struct ha
10 {
11     int y,next,v;
12 }e[15000];
13 void insert(int xx,int yy,int vv)
14 {
15     e[++len].next=link[xx];
16     link[xx]=len;
17     e[len].y=yy;
18     e[len].v=vv;
19 }
20 int spfa(int x)
21 {
22     memset(dis,10,sizeof(dis));
23     memset(book,0,sizeof(book));
24     dis[x]=0;   
25     book[x]=1;
26     q[1]=x;
27     int head=0,tail=1,sum=0;
28     while(head<tail)
29     {
30         int tn=q[++head];
31         book[tn]=0;
32         int te=link[tn];
33         for(int i=te;i;i=e[i].next)
34         {
35             int tmp=e[i].y;
36             if(dis[tmp]>dis[tn]+e[i].v)
37             {
38                 dis[tmp]=dis[tn]+e[i].v;
39                 if(!book[tmp])
40                 {
41                     book[tmp]=1;
42                     q[++tail]=tmp;
43                 }
44             }
45         }
46     }
47     for(int i=1;i<=n;i++)
48         sum+=dis[b[i]];
49     return sum;
50 }
51 int main()
52 {
53     cin>>n>>p>>c;
54     for(int i=1;i<=n;i++)
55         cin>>b[i];
56     int xx,yy,vv;
57     for(int i=1;i<=c;i++)
58     {
59         cin>>xx>>yy>>vv;
60         insert(xx,yy,vv);
61         insert(yy,xx,vv);
62     }
63     for(int i=1;i<=p;i++)
64         ans=min(spfa(i),ans);
65     cout<<ans<<endl;
66     return 0;
67 }
1215

 

易错点阿喂

1.邻接矩阵必须判断重边(看要最大值还是最小值)

2.邻接矩阵注意范围(5000以上就会爆)

不过可以用邻接表对拍

3.link是关键字,这个习惯要改掉!!

4.注意e数组的范围,无向图 e*2,有向图e 

 

---------------------分割线----------------------------

最小生成树。

prim

 1 void prim(int S)
 2 {
 3     memset(dis,10,sizeof(dis));
 4     memset(bok,0,sizeof(bok));
 5     bok[S]=1;
 6     for(int i=1;i<=n;i++)
 7         dis[i]=a[S][i];
 8     summ=0;
 9     for(int i=1;i<n;i++)
10     {
11         int minn=a[0][0],c=0;
12         for(int j=1;j<=n;j++)
13             if(minn>dis[j]&&bok[j]==0)
14             {
15                 minn=dis[j];
16                 c=j;
17             }
18         bok[c]=1;
19         summ+=minn;
20         for(int j=1;j<=n;j++)
21             if(dis[j]>a[c][j]&&bok[j]==0)
22                 dis[j]=a[c][j];
23     }
24 }
= =

kruskal

 1 /*
 2 by kaike
 3 11/16/2016
 4 */
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<cstring>
 8 #include<string>
 9 #include<cstdio>
10 using namespace std;
11 int kk=0,sum=0;
12 int getf(int v)
13 {
14     if(f[v]!=v)
15         f[v]=getf(f[v]);
16     return f[v];
17 }
18 int merge(int v,int u)
19 {
20     int t1=getf(v),t2=getf(u);
21     if(t1!=t2)
22     {    f[t2]=t1;
23         return 1;
24     }
25     return 0;
26 }
27 void kruskal()
28 {
29     for(int i=1;i<=n;i++)
30     {
31         if(meige(e[i].next,e[i].y))
32         {
33             kk++;
34             sum+=e[i].v;
35         }
36         if(kk==n-1) break;
37     }
38 }
39 int main()
40 {
41     kruskal();
42     cout<<sum<<endl;
43     return 0;
44 }
= =

 割点

 1 /*
 2 by kaike
 3 11/16/2016
 4 */
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<cstdio>
 8 #include<cstring>
 9 #include<string>
10 using namespace std;
11 const int MAXN=5010;
12 int n,e[MAXN][MAXN];
13 int num[MAXN],low[MAXN],bok[MAXN];
14 int root=1,ans=0,x,y,index=0;
15 void init()
16 {
17     cin>>n;
18     while(cin>>x>>y)
19     {
20         e[x][y]=1;
21         e[y][x]=1;
22     }
23 }
24 void dfnlow(int cur,int father)
25 {
26     int child=0;
27     index++;
28     num[cur]=index;
29     low[cur]=index;
30     for(int i=1;i<=n;i++)
31         if(e[cur][i]==1)
32         {
33             if(num[i]==0)
34             {
35                 child++;
36                 dfnlow(i,cur);
37                 low[cur]=min(low[cur],low[i]);
38                 if(cur!=root&& low[i]>=num[cur])
39                     bok[cur]=1;
40                 if(cur==root && child==2)
41                     bok[cur]=1;
42             }
43             else if(i!=father)
44                 low[cur]=min(low[cur],num[i]);
45         }
46 }
47 int main()
48 {
49     init();    
50     dfnlow(1,root);
51     for(int i=1;i<=n;i++)
52         if(bok[i]==1)   ans++;
53     cout<<ans<<endl;
54     for(int i=1;i<=n;i++)
55         if(bok[i]==1)  cout<<i<<endl;
56     return 0;
57 }
= =

割边

 1 /*
 2 by kaike
 3 11/16/2016
 4 */
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<cstring>
 8 #include<string>
 9 #include<cstdio>
10 using namespace std;
11 const int MAXN=5010;
12 int n,m,e[160][160],x,y,len=0;
13 int num[MAXN],low[MAXN],index=0,bok[MAXN],root=1;
14 struct qaq
15 {
16     int aa,bb;
17 }a[MAXN];
18 bool cmp(qaq x,qaq y)
19 {
20     return (x.aa<y.aa ||(x.aa==y.aa && x.bb<y.bb ));
21 }
22 void init()
23 {
24     cin>>n>>m;
25     for(int i=1;i<=m;i++)
26     {
27         cin>>x>>y;
28         e[x][y]=1;
29         e[y][x]=1;
30     }
31 }
32 void dfnlow(int cur,int father)
33 {
34     int child=0;
35     index++;
36     num[cur]=index;
37     low[cur]=index;
38     for(int i=1;i<=n;i++)
39         if(e[cur][i]==1)
40         {
41             if(num[i]==0)
42             {
43                 child++;
44                 dfnlow(i,cur);
45                 low[cur]=min(low[cur],low[i]);
46                 if(low[i]>num[cur])
47                 {   a[++len].aa=cur;
48                     a[len].bb=i;
49                 }
50             }
51             else if(i!=father)
52                 low[cur]=min(low[cur],num[i]);
53         }
54 }
55 int main()
56 {
57     init();
58     dfnlow(1,root);
59     sort(a+1,a+len+1,cmp);
60     for(int i=1;i<=len;i++)
61         cout<<a[i].aa<<' '<<a[i].bb<<endl;
62     return 0;
63 }
= =

 

有向图的强联通分量

无向图的边双联通分量

 

 

这样看来好像图也没有很难

不懂为什么学东西的时候遇到题目都不会

归根结底还是知识点不熟悉

感觉这样一总结都清晰了好多

不言谢

只赴汤蹈火

posted @ 2016-09-28 14:31  kaike  阅读(1048)  评论(3编辑  收藏  举报