• 靠二进制画几何[图论]


    @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.
    ");
    51         else printf("BICOLORABLE.
    ");
    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.
    ");
    73         else printf("NOT BICOLORABLE.
    ");
    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("
    ");
    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("
    ");
    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("
    ");
    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
    ");
    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
    ");
    60         else printf("1
    ");
    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
    ",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("
    ");
    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("
    ");
    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
    ");
    95     else printf("YES
    ");
    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 }
    = =

    有向图的强联通分量

    无向图的边双联通分量

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

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

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

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

    不言谢

    只赴汤蹈火

    No matter how you feel, get up , dress up , show up ,and never give up.
  • 相关阅读:
    脚本性能分析
    openwrt补丁
    定制openwrt的根文件
    openwrt路由器更换了Flash之后需要修改的源码
    openwrt驱动与应用程序的联系
    我的vi/vim配置文件
    Python中的字典分组函数(groupby,itertools)
    迭代器
    tuple
    list
  • 原文地址:https://www.cnblogs.com/Kaike/p/5916221.html
Copyright © 2020-2023  润新知