2016/6/1 第九届ACM大赛前夕模板总结

原创 2016年06月01日 19:12:23


一、最小生成树...............................................................................................................2

1、最小生成树:v + v + value布线问题.................................................................2

3prim算法之矩阵类型.........................................................................................4

4、输出最小生成树个边权值累加和(矩阵类型).....................................................5

5、求出最小生成树中边的最大值(矩阵类型)........................................................6

6prim算法变形之引水工程(矩阵型)完全矩阵...................................................8

7Kruskal(克鲁斯卡尔)(不是完全边,v+v+value..........................................9

8、还差多少对v+v才能达到最小生成树................................................................11

9、先判断是否畅通,再用最小生成树求最小花费..................................................12

10dfs欧拉回路.................................................................................................15

12、次小生成树(v+v+value型最小花费方案个数).............................................16

13、判断最小生成树是否唯一................................................................................19

13最优比率生成树 (最优比例生成树)................................................................21

14、判断边与一个图最小生成shu的关系.............................................................23

15hdu 3371 最小生成树(有重边)................................................................25

二、二分图....................................................................................................................26

1、两列相同数的最大匹配数(月老的难题).........................................................26

三、树状数组+线段树组................................................................................................27

1、士兵杀敌<1>(树状数组模板)........................................................................28

2士兵杀敌<2>(树状数组模板)......................................................................29

3、士兵杀敌(三)(rmq求区间最大最小值之差)..............................................30

4、第i个人的军功数.............................................................................................31

四、数组A[1..n]中超过半数的元素都相同时,该数组被称为含有主元素。...................32

五、 快排.....................................................................................................................33

1、数组排序..........................................................................................................33

2、快速排序一般版本(可求第K大元素)............................................................33

3归并排序求逆序数............................................................................................34

4求第k大的数.................................................................................................35

5RMQ模板 ,返回区间最值 、 最值的下标...................................................36

6快速幂求余模板................................................................................................37

7最长公共子序列..............................................................................................37

七、二分.......................................................................................................................39

八、最短路径................................................................................................................39

1、最短路径+畅通工程续.......................................................................................39

2、畅通工程再续...................................................................................................41

3、公交车最短路径(公交站是英文名字).............................................................42

22、最短路径 求最短距离..........................................................................................44

4、单源最短路Dijkstra算法。只不过起点给你多个,然后求可以到达的目的地中路径最短的一条   45

5、飘谊想知道他走完观光道路并回到源点的最短路径...........................................47

6、给多个坐标,求最短路径的最大边....................................................................48

7、最k短路..........................................................................................................50

8、一棵树上的任意两点的距离..............................................................................52

9、最短路径spfa..................................................................................................54

10aij矩阵类型的单源最短路径并且输出最短权值和最短路径.............................56

11、邻接矩阵的单源最短路径................................................................................58

九、最大流....................................................................................................................61

1、简单最大流.......................................................................................................61

2、现在要求从1点到n点在从n点返回1点的最短路..........................................63

十二、贪心问题.............................................................................................................65

4、拦截导弹..........................................................................................................65

5、最少拦截系统...................................................................................................66

5、心急的c小佳....................................................................................................66

7radar...............................................................................................................68

十三、几何问题.............................................................................................................69

1、点线距离..........................................................................................................69

2、是否是凸多边形................................................................................................69

3、点是否在凸多边形内或边上..............................................................................69

4、点在任意多边形内或边上..................................................................................69

十四、 kmp算法.........................................................................................................70

1、最小的匹配位置................................................................................................70

2、子串出现的次数................................................................................................71

 3、简单求周期......................................................................................................72

4、求最长的公共子串,要注意的是字典序最小......................................................73

5kmp算法模板(子串个数).............................................................................74

6、求S中最长回文串的长度.................................................................................75

7、容斥定理..........................................................................................................76

8、字典树的简单应用............................................................................................78

8括号匹配.........................................................................................................79

9、求一个字符串的最长递增子序列的长度.............................................................81

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

一、最小生成树

1、最小生成树:v + v + value布线问题

布线问题:由于安全问题,只能选择一个楼连接到外界供电设备。

/*

1

 

v e

4 64个顶点,正好六个边)

 

1 2 10

2 3 10

3 1 10

1 4 1

2 4 1

3 4 1

 

1 3 5 6(连接到外界供电设备所需要的费用)

*/

 

#include<iostream>

using namespace std;

#define MAX 505

#define MAXCOST 0x7fffffff

 

int graph[MAX][MAX];

 

int prim(int graph[][MAX], int n)

{

      int lowcost[MAX];

      int mst[MAX];

      int i, j, min, minid, sum =0;

      for (i = 2; i <= n; i++)

      {

             lowcost[i] = graph[1][i];

             mst[i] = 1;

      }

      mst[1] = 0;

      for (i = 2; i <= n; i++)

      {

             min = MAXCOST;

             minid = 0;

             for (j = 2; j <= n;j++)

             {

                    if (lowcost[j]< min && lowcost[j] != 0)

                    {

                           min =lowcost[j];

                           minid =j;

                    }

             }

             //cout <<"V" << mst[minid] << "-V" << minid<< "=" << min << endl;

             sum += min;

             lowcost[minid] = 0;

             for (j = 2; j <= n;j++)

             {

                    if(graph[minid][j] < lowcost[j])

                    {

                           lowcost[j]= graph[minid][j];

                           mst[j] =minid;

                    }

             }

      }

      return sum;

}

 

int main()

{

      int i, j, k, m, n;

      int x, y, cost;

      int zushu;

      cin>>zushu;

      while(zushu--)

      {

          cin >> m >> n;//m=顶点的个数,n=边的个数

             for (i = 1; i <= m;i++)

             {

                    for (j = 1; j<= m; j++)

                    {

                           graph[i][j]= MAXCOST;

                    }

             }

             for (k = 1; k <= n;k++)

             {

                    cin >> i>> j >> cost;

                    graph[i][j] =cost;

                    graph[j][i] =cost;

             }

          cost = prim(graph, m);

         

          int min_v=MAXCOST;

             for(inti=1;i<=m;++i)

             {

                    int t;

                 cin>>t;

                    if(t<min_v)

                    min_v=t;

             }

             

          cout <<cost+min_v<< endl;

      }

      return 0;

}

 

 

3prim算法之矩阵类型

/*

1(组数)

 

33*3的矩阵)

0 990 692

990 0 179

692 179 0

 

//一个有n个顶点的无向图最多几条边 n(n-1)/2

//具有n个顶点的无向图,至少应有多少n-1条边才能确保是一个连通图

 

*/

 

#include "stdio.h"

#include "string.h"

#define N 500

#define INT 10000

bool vis[N];

int dis[N];

int a[N][N];

int main(){

      int t;

      scanf("%d",&t);

      while(t--){

             int n;

             scanf("%d",&n);

             int i,j,temp,k;

             memset(vis,0,sizeof(vis));

             for(i=1;i<=n;++i){

                    for(j=1;j<=n;++j){

                           scanf("%d",&a[i][j]);

                    }

             }

             for(i=1;i<=n;++i){

                    dis[i]=INT;

             }

             dis[1]=0;

             for(i=1;i<=n;++i){

                    temp=INT;

                    k=0;

                    for(j=1;j<=n;++j){

                    if(!vis[j]&&dis[j]<temp){

                           temp=dis[j];

                           k=j;

                    }

                    }

                    vis[k]=1;

                    for(j=1;j<=n;++j){

                           if(!vis[j]&&dis[j]>a[k][j]){

                                  dis[j]=a[k][j];

                           }

                    }

             }

             int max=0;

             for(i=1;i<=n;++i){

                    if(max<dis[i])

                           max=dis[i];

             }

             printf("%d\n",max);

      }

      return 0;

}

 

4、输出最小生成树个边权值累加和(矩阵类型)

4

0 4 9 21

4 0 8 17

9 8 0 16

21 17 16 0

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 110

int map[N][N],low[N],visited[N];

int n;

 

int prim()

{

   int i,j,pos,min,result=0;

   memset(visited,0,sizeof(visited));

   visited[1]=1;pos=1;

   for(i=1;i<=n;i++)

       if(i!=pos)low[i]=map[pos][i];

   for(i=1;i<n;i++)

   {

    min=MaxInt;

    for(j=1;j<=n;j++)

        if(visited[j]==0&&min>low[j])

        {

            min=low[j];pos=j;

        }

   result+=min;

   visited[pos]=1;

//更新权值

   for(j=1;j<=n;j++)

       if(visited[j]==0&&low[j]>map[pos][j])

           low[j]=map[pos][j];

   }

   return result;

}

 

int main()

{

   int i,v,j,ans;

   while(scanf("%d",&n)!=EOF)

   {

       memset(map,MaxInt,sizeof(map));

       for(i=1;i<=n;i++)

           for(j=1;j<=n;j++)

           {

               scanf("%d",&v);

               map[i][j]=map[i][j]=v;

           }

           ans=prim();

           printf("%d\n",ans);

   }

   return 0;

}

 

 

 

 

5、求出最小生成树中边的最大值(矩阵类型)

1

3

0 990 692

990 0 179

692 179 0

 

 

692

 

 

 

 

#include<stdio.h>

#define MAX 505

#define inf 999999

int c[MAX][MAX];

int n;

 

 

void prim()

{

   int lowcost[MAX ];

   int closest[MAX ];

   bool s[MAX ];

   s[1]=true;

   for(int i=2;i<=n;i++)

   {

       lowcost[i]=c[1][i];

       closest[i]=1;

       s[i]=false;

   }

   for(int i=1;i<=n;i++)

   {

       int min=inf;

       int j=i;

       for(int k=2;k<=n;k++)

       if((lowcost[k]<min)&&(!s[k]))

       {

           min=lowcost[k];

           j=k;

       }

 

 

 

 

 

 

      //cout<<j<<" "<<closet[j]<<endl;输出最小生成树的路径。

 

 

       s[j]=true;

       for(int k=2;k<=n;k++)

       {

           if((c[j][k]<lowcost[k])&&(!s[k]))

           {

               lowcost[k]=c[j][k];

               closest[k]=j;

           }

       }

   }

 

 

 

 

//最小生成树的边值已经放大lowcost数组中了。遍历一下就可以得到最大最小值。

   int result=-1;

   for(int i=2;i<=n;i++)

      {

          if(result<lowcost[i])

           result=lowcost[i];

      }

      printf("%d\n",result);

}

int main()

{

   int t;

   scanf("%d",&t);

   while(t--)

   {

       scanf("%d",&n);

       for(int i=1;i<=n;i++)

       {

           for(int j=1;j<=n;j++)

           {

               scanf("%d",&c[i][j]);

           }

       }

       prim();

   }

   return 0;

}

 

 

 

 

6prim算法变形之引水工程(矩阵型)完全矩阵

 /*1

      5

 0 5 4 4 3 6

 5 0 2 2 2 2

 420 3 3 3

 423 0 4 5

 323 4 0 1

 523 5 1 0*/

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 303

int map[N][N],low[N],visited[N];

int n;

 

int prim()

{

   int i,j,pos,min,result=0;

   memset(visited,0,sizeof(visited));

   visited[1]=1;pos=1;

   for(i=1;i<=n;i++)

       if(i!=pos)low[i]=map[pos][i];

   for(i=1;i<n;i++)

   {

    min=MaxInt;

    for(j=1;j<=n;j++)

        if(visited[j]==0&&min>low[j])

        {

            min=low[j];

                     pos=j;

        }

   result+=min;

   visited[pos]=1;

   for(j=1;j<=n;j++)

       if(visited[j]==0&&low[j]>map[pos][j])

           low[j]=map[pos][j];

   }

   return result;

}

 

int main()

{

   int i,v,j,ans,zushu;

   scanf("%d",&zushu);

   int a[303];

   while(zushu--)

   {

       

       scanf("%d",&n);

       memset(map,MaxInt,sizeof(map));

       

       map[1][1]=0;

       for(i=2;i<=n+1;++i)

       {

               scanf("%d",&map[i][1]);

               map[1][i]=map[i][1];

       }

      

       getchar();

       for(i=2;i<=n+1;i++)

           for(j=2;j<=n+1;j++)

           {

               scanf("%d",&v);

               map[i][j]=map[i][j]=v;

           }

           

       

       n=n+1;

        ans=prim();

          printf("%d\n",ans);

   }

   return 0;

}

 

 

       

7Kruskal(克鲁斯卡尔)(不是完全边,v+v+value

/*

但不一定有直接的公路相连,只要能间接通过公路可达即可

村庄从1M编号。当N0时,全部输入结束,相应的结果不要输出。

对每个测试用例,在1行里输出全省畅通需要的最低成本。

若统计数据不足以保证畅通,则输出“?”。

Sample Input

 

3 3

1 2 1

1 3 2

2 3 4

 

1(e) 3(v)

2 3 2

0 100

 

 

Sample Output

3

?

*/

 

 

 

#include<iostream>

#include<cstring>

#include<string>

#include<cstdio>

#include<algorithm>

using namespace std;

#define MAX 100

int father[MAX], son[MAX];

int v, l;

 

typedef struct Kruskal //存储边的信息

{

      int a;

      int b;

      int value;

};

 

bool cmp(const Kruskal & a, const Kruskal & b)

{

      return a.value < b.value;

}

 

int unionsearch(int x) //查找根结点+路径压缩

{

      return x == father[x] ? x :unionsearch(father[x]);

}

 

bool join(int x, int y) //合并

{

      int root1, root2;

      root1 = unionsearch(x);

      root2 = unionsearch(y);

      if(root1 == root2) //为环

             return false;

      else if(son[root1] >=son[root2])

             {

                    father[root2] =root1;

                    son[root1] +=son[root2];

             }

             else

             {

                    father[root1] =root2;

                    son[root2] +=son[root1];

             }

      return true;

}

 

int main()

{

      int ltotal, sum, flag;

      Kruskal edge[MAX];

      //scanf("%d",&ncase);

      while(scanf("%d%d",&l, &v),l)

      {

             ltotal = 0, sum = 0,flag = 0;

             for(int i = 1; i <=v; ++i) //初始化

             {

                    father[i] = i;

                    son[i] = 1;

             }

             for(int i = 1; i <=l ; ++i)

             {

                    scanf("%d%d%d",&edge[i].a, &edge[i].b, &edge[i].value);

             }

             sort(edge + 1, edge +1 + l, cmp); //按权值由小到大排序

             

             int count=0;

             

             for(int i = 1; i <=l; ++i)

             {

                    if(join(edge[i].a,edge[i].b))

                    {

                           ltotal++;//边数加1

                           sum +=edge[i].value; //记录权值之和

                           //cout<<edge[i].a<<"->"<<edge[i].b<<endl;

                    }

                    if(ltotal == v- 1) //最小生成树条件:边数=顶点数-1

                    {

                           flag =1;

                           break;

                    }

                    count++;

             }

              //printf("count%d\n", count);

             if(flag)

             printf("%d\n",sum);

             else

             printf("?\n");

             

      }

      return 0;

}

8、还差多少对v+v才能达到最小生成树

/*

 

目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,

只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

v e

 

4 2

1 3

4 3

 

3 3

1 2

1 3

2 3

 

5 2

1 2

3 5

 

999 0

0

输出最少还需要建设的道路数目。

*/

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

int pre[1010];

 

int unionsearch(int root) //查找父节点+路径压缩(非递归)

{

   int son, tmp;

   son = root;

   while(root != pre[root])

       root = pre[root];

   while(son != root)

   {

       tmp = pre[son];

       pre[son] = root;

       son = tmp;

   }

   return root;

}

 

/*int unionsearch(int root) //查找父节点+路径压缩(递归)

{

      return root == pre[root] ?root : unionsearch(pre[root]);

}*/

 

int main()

{

   int num, road, total, i, start,end, root1, root2;

   while(scanf("%d%d",&num, &road) && num)

   {

       total = num - 1;

       for(i = 1; i <= num;++i)

           pre[i] = i;

       while(road--)

       {

           scanf("%d%d",&start, &end);

           root1 =unionsearch(start);

           root2 =unionsearch(end);

           if(root1 != root2)

           {

               pre[root1] = root2;

               total--;

           }

       }

       printf("%d\n",total);

   }

   return 0;

}

 

9、先判断是否畅通,再用最小生成树求最小花费

/*

对每个测试用例, 1行里输出全省畅通需要的最低成本。

若统计数据不足以保证畅通,则输出 No solution

2

e v

3 3

1 2 1

1 3 2

2 3 4

 

 

1 3

2 3 2

样例输出

3

No solution

*/

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

//判断是否畅通

int pre[1010];

int unionsearch(int root) //查找父节点+路径压缩(非递归)

{

   int son, tmp;

   son = root;

   while(root != pre[root])

       root = pre[root];

   while(son != root)

   {

       tmp = pre[son];

       pre[son] = root;

       son = tmp;

   }

   return root;

}

//最小生成树

 

#define MAX 505

#define MAXCOST 0x7fffffff

int graph[MAX][MAX];

 

int prim(int graph[][MAX], int n)

{

      int lowcost[MAX];

      int mst[MAX];

      int i, j, min, minid, sum =0;

      for (i = 2; i <= n; i++)

      {

             lowcost[i] =graph[1][i];

             mst[i] = 1;

      }

      mst[1] = 0;

      for (i = 2; i <= n; i++)

      {

             min = MAXCOST;

             minid = 0;

             for (j = 2; j <= n;j++)

             {

                    if (lowcost[j]< min && lowcost[j] != 0)

                    {

                           min =lowcost[j];

                           minid =j;

                    }

             }

             //cout <<"V" << mst[minid] << "-V" << minid<< "=" << min << endl;

             sum += min;

             lowcost[minid] = 0;

             for (j = 2; j <= n;j++)

             {

                    if(graph[minid][j] < lowcost[j])

                    {

                           lowcost[j]= graph[minid][j];

                           mst[j] =minid;

                    }

             }

      }

      return sum;

}

 

int main()

{

   int num, road, total, start,end, root1, root2;

   

   int i, j, k, m, n;

      int x, y, cost;

      int zushu;

      cin>>zushu;

      

      while(zushu--)

      {

          cin >> n >> m ;//m=顶点的个数,n=边的个数

          num=m,road=n;

             

             for (i = 1; i <= m;i++)

             {

                    for (j = 1; j<= m; j++)

                    {

                           graph[i][j]= MAXCOST;

                    }

             }

             

             

             //------------判断是否畅通

          //num顶点,road道路

       total = num - 1;

       for(i = 1; i <= num;++i)

           pre[i] = i;

           

           

             for (k = 1; k <= n;k++)

             {

                    cin >> i>> j >> cost;

                    graph[i][j] =cost;

                    graph[j][i] =cost;

                    start=i;

                    end=j;

                    root1 =unionsearch(start);

           root2 =unionsearch(end);

           if(root1 != root2)

           {

               pre[root1] = root2;

               total--;

           }

             }

      

       //cout<<total<<endl;

       if(total<1)

       {

               cost = prim(graph, m);

               printf("%d\n",cost);

       }

       else{

              printf("No solution\n");

       }

      }

   return 0;

}

 

10dfs欧拉回路

/*

2

v e

4 3

 

1 2

1 3

1 4

 

一笔画就yes,不一笔画no

*/

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <vector>

#include <climits>

#include <algorithm>

#include <cmath>

#define LL long long

using namespace std;

vector<int>e[1010];

int deg[1010];

bool vis[1010];

void dfs(int u) {

   vis[u] = true;

   for(int i = 0; i <e[u].size(); i++) {

       if(!vis[e[u][i]]) {

           dfs(e[u][i]);

       }

   }

}

int main() {

   int kase,p,q,i,u,v,temp;

   bool flag;

   scanf("%d",&kase);

   while(kase--) {

       scanf("%d%d",&p,&q);

       memset(deg,0,sizeof(deg));

       memset(vis,false,sizeof(vis));

       for(i = 0; i < 1010;i++)

           e[i].clear();

       for(i = 0; i < q; i++) {

           scanf("%d%d",&u,&v);

           e[u].push_back(v);

           e[v].push_back(u);

           deg[u]++;

           deg[v]++;

       }

       dfs(1);

       flag = true;

       for(i = 1; i <= p; i++)

           if(!vis[i]) {

               flag = false;

               break;

           }

       if(flag) {

           for(temp = 0,i = 1; i<= p; i++) {

               if(deg[i]&1) {

                   temp++;

                   if(temp > 2)break;

               }

           }

       }

       if(!flag || temp > 2)puts("No");

       else puts("Yes");

   }

   return 0;

}

 

 

      

12、次小生成树(v+v+value型最小花费方案个数)

 

 

/*N个不同的城市里,这些城市分别编号1~N

如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)

样例输入

2(组数)

 

3v 3e

v+v+value

1 2 1

2 3 2

3 1 3

 

4 4

1 2 2

2 3 2

3 4 2

4 1 2

样例输出

No

Yes

*/

 

#include<iostream>

#include<stdio.h>

#include<string>

#include<cstring>

#include<algorithm>

using namespace std;

#define MaxV 510

#define MaxE 200005

struct Edge

{

 int x,y,dis;

};

Edge edge[MaxE],edge1[MaxE];       //分别是边数组 最小生成树中的边数组

int father[MaxV],Num[MaxV],num,dex,dey;        //并查集 num统计生成树边的条数 dex dey指枚举删除边的x,y坐标

void Init(int V)        //并查集初始化,单个元素自成集合

{

 for(int i=1;i<=V;i++)

 {

 father[i]=i;

 Num[i]=1;

 }

}

int findfather(int x)     //寻找父结点,可以压缩路径。。

{

 for(x;x!=father[x];x=father[x]) ;

 return father[x];

}

void Union(int x,int y)

{

 int t1,t2;

 t1=findfather(x);

 t2=findfather(y);

 if(Num[t1]>Num[t2])

 {

 father[t2]=t1;

 Num[t1]+=Num[t2];

 }

 else

 {

 father[t1]=t2;

 Num[t2]+=Num[t1];

 }

}

int comp(const void* p1,const void* p2)

{

 return(*(Edge*)p1).dis>(*(Edge*)p2).dis;

}

int Krusual(int V,int E)

{

 int sum=0;

 for(int i=1;i<=E;i++)

 {

 if(findfather(edge[i].x)!=findfather(edge[i].y))

 {

  sum+=edge[i].dis;

  Union(edge[i].x,edge[i].y);

  edge1[++num]=edge[i];

 }

 }

 return sum;

}

int AKrusual(int V,int E)

{

 Init(V);

 int sum=0;

 qsort(edge+1,E,sizeof(edge[1]),comp);

 int k;

 for(k=1;k<=E;++k)

 {

 if(findfather(edge[k].x)!=findfather(edge[k].y))

 {

  if(edge[k].x==dex&&edge[k].y==dey)

  {continue;}

  if(edge[k].x==dey&&edge[k].x==dex)

  {continue;}

  sum+=edge[k].dis;

  Union(edge[k].x,edge[k].y);

 }

 }

 return sum;

}

bool Judge(int V)     //判断图是否连通,不连通则无法构造最小生成树

{

 for(int m=1;m<=V-1;++m)

 if(findfather(m)!=findfather(m+1))

 return false;

 return true;

}

int main()

{

 int test,j,V,E;

 scanf("%d",&test);

 while(test--)

 {

 scanf("%d%d",&V,&E);

 num=0;

 for(j=1;j<=E;++j)

 {

  scanf("%d%d%d",&edge[j].x,&edge[j].y,&edge[j].dis);

 }

 qsort(edge+1,E,sizeof(edge[1]),comp);

 Init(V);

 int sum=Krusual(V,E);

 int M=1000,temp;

 for(int q=1;q<=num;++q)

 {

  dex=edge1[q].x;

  dey=edge1[q].y;

  temp=AKrusual(V,E);

  if(temp<M&&Judge(V))

  M=temp;

  if(M==sum) break;

 }

 if(M==sum)printf("Yes\n");

 else printf("No\n");

 }

} 

 

 

 

 

/*

13、判断最小生成树是否唯一

   构成原最小生成树的边,一条边一条边的删。

*/

 

 

#include"stdio.h"

#include"stdlib.h"

 

 

struct A

{

      int a,b;

      int flag;

      int len;

}eage[5555];

int n,m;

int set[111];

 

 

int cmp(const void *a,const void *b)

{

      struct A *c,*d;

      c=(struct A *)a;

      d=(struct A *)b;

      return c->len-d->len;

}

 

 

void build(int num)

{

      int i;

      for(i=1;i<=num;i++)  set[i]=i;

}

int find(int k)

{

      if(set[k]==k) return k;

      set[k]=find(set[k]);

      return set[k];

}

void Union(int f1,int f2)

{

      set[f1]=f2;

}

 

 

int Kruskal(int t_d)

{

      int i;

      int ans;

      int f1,f2;

      int count=1;

 

 

      ans=0;

      for(i=0;i<m;i++)

      {

             if(count==n)break;

             if(i==t_d)      continue;

             f1=find(eage[i].a);

             f2=find(eage[i].b);

             if(f1==f2)     continue;

             Union(f1,f2);

             eage[i].flag=1;

             ans+=eage[i].len;

             count++;

      }

 

 

      return ans;

}

 

 

int main()

{

      int T;

      int z,i;

      int a,b,c;

      int ans,t_ans;

      int del[111],k;

      int flag;

      int temp;

 

 

      scanf("%d",&T);

      while(T--)

      {

             scanf("%d%d",&n,&m);

//m e n v

 

             build(n);

 

 

             for(i=0;i<m;i++)

             {

                    scanf("%d%d%d",&a,&b,&c);

                    eage[i].a=a;

                    eage[i].b=b;

                    eage[i].len=c;

                    eage[i].flag=0;

             }

 

 

             qsort(eage,m,sizeof(eage[0]),cmp);

             ans=Kruskal(-1);

             temp=0;

             for(i=1;i<=n;i++)if(set[i]==i)   temp++;

             if(temp>1)   {printf("0\n");continue;}

             k=0;

             for(i=0;i<m;i++) if(eage[i].flag)     del[k++]=i;

 

 

             flag=0;

             for(z=0;z<k;z++)

             {

                    build(n);

                    t_ans=Kruskal(del[z]);

                    temp=0;

                    for(i=1;i<=n;i++)if(set[i]==i)   temp++;

                    if(temp>1)   continue;

                    if(t_ans==ans)    {flag=1;break;}

             }

 

 

             if(flag)   printf("Not Unique!\n");

             else       printf("%d\n",ans);

      }

      return 0;

}

 

 

经典问题:对于每一条边存在两个权值,分别是花费和长度,要生成一个树,使得总的花费比上总的长度最小。  

      

13、最优比率生成树 (最优比例生成树)

 

 

 

/*

 

4(v)

x y z

0 0 0

0 1 1

1 1 2

1 0 3

0

 

cost[i][j]=cost[j][i]=abs(z[i]-z[j]);//花费为海拔之差

dist[i][j]=dist[j][i]=sqrt(t);//距离为 点与点的水平距离

output: the minimum ratio ofoverall cost of the channels to the total length

*/

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

#include<queue>

using namespace std;

#define N 1010

#define MAX 999999999

const double eps=1e-4;

int n;

int vis[N],x[N],y[N],z[N],pre[N];

double dis[N],cost[N][N],dist[N][N];

double prim(double x){

   double totalcost=0,totaldist=0;

   for(int i=1;i<=n;i++){

       pre[i]=1;

   }

   dis[1]=0;

   memset(vis,0,sizeof(vis));

   vis[1]=1;

   for(int i=2;i<=n;i++){

       dis[i]=cost[1][i]-dist[1][i]*x;

   }

   int k;

   for(int i=2;i<=n;i++){

       double mincost=MAX;

       for(int j=2;j<=n;j++){

           if(!vis[j]&&dis[j]<mincost){

               mincost=dis[j];

               k=j;

           }

       }

       vis[k]=1;

       totalcost+=cost[pre[k]][k];

       totaldist+=dist[pre[k]][k];

       for(int j=1;j<=n;j++){

           if(!vis[j]&&dis[j]>cost[k][j]-dist[k][j]*x){

               dis[j]=cost[k][j]-dist[k][j]*x;

               pre[j]=k;

           }

       }

   }

   return totalcost/totaldist;

}

int main(){

   while(scanf("%d",&n),n){

       for(int i=1;i<=n;i++){

           scanf("%d%d%d",&x[i],&y[i],&z[i]);

           for(intj=1;j<i;j++){

               doublet=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);

               

               

               cost[i][j]=cost[j][i]=abs(z[i]-z[j]);//花费为海拔之差

               dist[i][j]=dist[j][i]=sqrt(t);//距离为 点与点的水平距离

           }

       }

       double a=0;

       while(1){

           double b=prim(a);

           if(abs(a-b)<eps)break;

           else a=b;

           //cout<<a<<endl;

       }

       printf("%.3f\n",a);

   }

   return 0;

}

 

 

14、判断边与一个图最小生成shu的关系

 

题意:给出一张带权无向图,然后询问该图的每条边进行询问,若这条边出现在该图的所有最小生成树中,输出any;若这条边可以出现在这张图的某几个最小生成树中,输出at least once;若这条边不会出现在这张图的任意一个最小生成树中,输出none

 

 

/*

 

input

4 5

1 2 101

1 3 100

2 3 2

2 4 2

3 4 1

output

none

any

at least one

at least one

any

*/

 

 

#include <iostream>

#include <cstdio>

#include <cstring>

#include <algorithm>

#define maxn 100010

using namespace std;

 

struct Edge{

   int from,to,dist,id;

}a[maxn];

 

int first[maxn],v[maxn*2],next[maxn*2],id[maxn*2];

int ans[maxn],fa[maxn],pre[maxn],dfs_clock,e;

 

int cmp(Edge a,Edge b){

   return a.dist < b.dist;

}

void init(){

   e = 0;

   memset(first,-1,sizeof(first));

}

 

void add_edge(int a,int b,int ID){

   v[e] = b;

   next[e] = first[a];

   id[e] = ID;

   first[a] = e++;

}

 

int dfs(int u,int fa_id){

   int lowu = pre[u] =++dfs_clock;

   for(int i = first[u];i != -1;i= next[i]){

       if(!pre[v[i]]){

           int lowv =dfs(v[i],id[i]);

           lowu = min(lowu,lowv);

           if(lowv >pre[u])  ans[id[i]] = 1;

       }else if(pre[v[i]] <pre[u] && id[i] != fa_id){

           lowu =min(lowu,pre[v[i]]);

       }

   }

   return lowu;

}

 

int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}

 

void join(int x,int y){

   int fx = find(x);

   int fy = find(y);

   if(fx != fy){

       e = 0;

       first[fx] = first[fy] = -1;

       pre[fx] = pre[fy] = 0;

       fa[fx] = fy;

   }

}

 

int main()

{

   int n,m;

   scanf("%d%d",&n,&m);

   init();

   for(int i = 1;i <=n;i++)  fa[i] = i;

   dfs_clock = 0;

   for(int i = 0;i < m;i++){

       scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].dist);

       a[i].id = i;

   }

   sort(a,a+m,cmp);

   memset(pre,0,sizeof(pre));

   memset(ans,0,sizeof(ans));

   for(int i = 0;i < m;i++){

       int j = i+1;

       while(j < m &&a[i].dist == a[j].dist)   j++;

       for(int k = i;k <j;k++){

           int fx =find(a[k].from);

           int fy = find(a[k].to);

           if(fx != fy){

               add_edge(fx,fy,a[k].id);

               add_edge(fy,fx,a[k].id);

               ans[a[k].id] = 2;

           }

       }

       for(int k = i;k <j;k++){

           int fx =find(a[k].from);

           int fy = find(a[k].to);

           if(fx != fy &&!pre[fx]){

               dfs(fx,-1);

           }

       }

       for(int k = i;k <j;k++){

           join(a[k].from,a[k].to);

       }

       i = j - 1;

   }

   for(int i = 0;i < m;i++){

       if(ans[i] == 0)printf("none\n");

       else if(ans[i] == 1)   printf("any\n");

       else   printf("at least one\n");

   }

   return 0;

}

 

 

 

15hdu 3371 最小生成树(有重边)

 

/*

the cities are signed from 1 to n.

1

6( survived cities) 4(you can choose to connect the cities ) 3(stillconnected cities)

it takes c to connect p and q

p q c

1 4 2

2 6 1

2 3 5

3 4 33

the number of this connected citie(2ge 2ge 3ge)

2 1 2

2 1 3

3 4 5 6

 

Output

For each case, output the least money you need to take, if its impossible, just output -1.

*/

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

int n,m,k,p[505],ans;

struct node{

   int u,v,w;

}pt[250000];

int cmp(node a,node b)

{

   return a.w<b.w;

}

int find(int x){return p[x]==x?x:p[x]=find(p[x]);}

int main()

{

   int t;

   scanf("%d",&t);

   while(t--)

   {

       int i,j,num,a,b,root,x,y;

       for(i=0;i<=500;i++)p[i]=i;

       bool flag=false;

       scanf("%d%d%d",&n,&m,&k);

       for(i=1;i<=m;i++)scanf("%d%d%d",&pt[i].u,&pt[i].v,&pt[i].w);

       sort(pt+1,pt+m+1,cmp);

       for(i=1;i<=k;i++)

       {

           scanf("%d%d",&num,&root);

           for(j=1;j<num;j++)

           {

               scanf("%d",&a);

                x=find(a),y=find(root);

               if(x!=y) p[x]=y;

           }

       }

       for(num=0,i=1;i<=n;i++)if(p[i]==i) num++;

       for(ans=0,i=1;i<=m;i++)

       {

           x=find(pt[i].u);y=find(pt[i].v);

           if(x!=y)

           {

               p[x]=y;

               ans+=pt[i].w;num--;

           }

           if(num==1)

           {

               flag=true;

               break;

           }

       }

       if(flag)printf("%d\n",ans);

       elseprintf("-1\n");

   }

   return 0;

}

二、二分图

1、两列相同数的最大匹配数(月老的难题)

/*

1

3(33) 4(可能关系)

(男女)

1 1

1 3

2 2

3 2

 

*/

#include<cstdio>

#include<cstring>

using namespace std;

#define N 10010

#define M 510

int head[M], next[N], key[N], num;

int match[M];

bool use[M];

 

void add(int u, int v) //hash表存图

{

      key[num] = v;

      next[num] = head[u];

      head[u] = num++;

}

 

bool find(int u) //匈牙利算法

{

      int temp;

      for(int i = head[u]; i != -1;i = next[i])

      {

             temp = key[i];

             if(!use[temp])

             {

                    use[temp] = true;

                    if(match[temp]== -1 || find(match[temp])) //增广路

                    {

                           match[temp]= u;

                           returntrue;

                    }

             }

      }

      return false;

}

 

int sum(int n) //最大匹配数

{

      int sumall = 0;

      for(int i = 1; i <= n;++i)

      {

             memset(use, false,sizeof(use));

             if(find(i))

                    sumall++;

      }

      return sumall;

}

 

int main()

{

      int ncase;

      int allnum, relation;

      int u, v;

      scanf("%d",&ncase);

      while(ncase--)

      {

             num = 0;

             memset(head, -1,sizeof(head));

             memset(match, -1,sizeof(match));

             scanf("%d%d",&allnum, &relation);

             for(int i = 0; i <relation; ++i)

             {

                    scanf("%d%d",&u, &v);

                    add(u, v);

             }

             printf("%d\n",sum(allnum));

      }

      return 0;

}

 

 

 

三、树状数组+线段树组

/*

1、士兵杀敌<1>(树状数组模板)

 

/*

5(士兵数) 2(询问数)

 

i个人杀的人数ai

1 2 3 4 5

 

m号到第n号士兵的总杀敌数

1 3

2 4

 

*/

#include<iostream>

#include<cstdio>

using namespace std;

int C[1000006];//保存树状数组

int n;//元素个数(即节点个数),下标从1开始

//求最小幂2k次幂

int lowbit(int t){ return t&(t^(t-1)); }

//求前n项和

int sum(int end)

{

      int sum=0;

      while(end>0)

      {

             sum+=C[end];

             end-=lowbit(end);//或也可end^=Lowbit(end);

      }

      return sum;

 }

 //对某个元素进行加减法操作

 void Plus(int pos,int num)

 {

     while(pos<=n)

     {

            C[pos]+=num;

            pos+=lowbit(pos);

       }

}

int main()

{

      int zishu,i;

      scanf("%d%d",&n,&zishu);

      for(i=1;i<=n;++i)

      {

             int temp;

             scanf("%d",&temp);//输入原始序列的第i个元素

             Plus(i,temp);// i个元素在原来为零的基础上加上temp

      }

      while(zishu--)

      {

             int min,max;

             scanf("%d%d",&min,&max);

             printf("%d\n",sum(max)-sum(min-1));

       }

      return 0;

}

 

2、士兵杀敌<2>(树状数组模板)

 

 

/*

5(士兵) 6(询问)

每个士兵的杀人个数

1 2 3 4 5

 

QUERY 1 3

ADD 1 2

QUERY 1 3

ADD 2 3

QUERY 1 2

QUERY 1 5

*/

#include<iostream>

#include<cstdio>

using namespace std;

int C[1000006];//保存树状数组

int n;//元素个数(即节点个数),下标从1开始

//求最小幂2k次幂

int lowbit(int t){ return t&(t^(t-1)); }

//求前n项和

int sum(int end)

{

      int sum=0;

      while(end>0)

      {

             sum+=C[end];

             end-=lowbit(end);//或也可end^=Lowbit(end);

      }

      return sum;

 }

 //对某个元素进行加减法操作

 void Plus(int pos,int num)

 {

     while(pos<=n)

     {

            C[pos]+=num;

            pos+=lowbit(pos);

       }

}

int main()

{

      int zishu,i;

      scanf("%d%d",&n,&zishu);

      for(i=1;i<=n;++i)

      {

             int temp;

             scanf("%d",&temp);//输入原始序列的第i个元素

             Plus(i,temp);// i个元素在原来为零的基础上加上temp

      }

      while(zishu--)

      {

             int min,max;

             char ch[10];

             scanf("%s %d%d",ch,&min,&max);

       if(ch[0]=='Q')

       printf("%d\n",sum(max)-sum(min-1));

             else

             Plus(min,max);

       }

      return 0;

}

3、士兵杀敌(三)(rmq求区间最大最小值之差)

/*

 

5 2

 

1 2 6 9 3

第一个数到第二个数之间最大最小值之差

1 2

2 4

 

*/

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

 

const int N = 100010;

int maxsum[20][N], minsum[20][N]; //优化1

 

void RMQ(int num) //预处理->O(nlogn)

{

      for(int i = 1; i != 20; ++i)

             for(int j = 1; j <=num; ++j)

                    if(j + (1<< i) - 1 <= num)

                    {

                           maxsum[i][j]= max(maxsum[i - 1][j], maxsum[i - 1][j + (1 << i >> 1)]); //优化2

                           minsum[i][j] = min(minsum[i - 1][j],minsum[i - 1][j + (1 << i >> 1)]);

                    }

}

 

int main()

{

      int num, query;

      int src, des;

      scanf("%d %d",&num, &query);

      for(int i = 1; i <= num;++i) //输入信息处理

      {

             scanf("%d",&maxsum[0][i]);

             minsum[0][i] = maxsum[0][i];

      }

      RMQ(num);

      while(query--) //O(1)查询

      {

             scanf("%d%d", &src, &des);

             int k = (int)(log(des- src + 1.0) / log(2.0));

             int maxres =max(maxsum[k][src], maxsum[k][des - (1 << k) + 1]);

             int minres =min(minsum[k][src], minsum[k][des - (1 << k) + 1]);

             printf("%d\n",maxres - minres);

      }

      return 0;

}       

 

 

4、第i个人的军功数

 

/*

 

4 (指令) 10(士兵)

起始时所有人的军功都是0.

 

 

ADD 1 3 10  //ADD 1 3 10表示,第1个人到第3个人请战,最终每人平均获得了10军功

QUERY 3

ADD 2 6 50

QUERY 3     //QUERY 3 表示南将军在询问第3个人的军功是多少。

 

样例输出

10

60

*/

 

 

#include<cstdio>

#include<cstring>

const int M=1000010;

int data[M];

int Max;

inline int LowBit(int n)

{

      return n&(-n);

}

void Plus(int n,int value) //n项每项增加value

{

      while(n>0)

      {

             data[n]+=value;

             n-=LowBit(n);

      }

}

int Get(int n) //获取每个位置的值

{

      int sum=0;

      while(n<=Max)

      {

             sum+=data[n];

             n+=LowBit(n);

      }

      return sum;

}

char cmd[50];

int main()

{

      int n,a,b,v;

      scanf("%d%d",&n,&Max);

      while(n--)

      {

             scanf("%s",cmd);

             if(!strcmp(cmd,"ADD"))

             {

                    scanf("%d%d%d",&a,&b,&v);

                    Plus(a-1,-v);

                    Plus(b,v);

             }

             else

             {

                    scanf("%d",&a);

                    printf("%d\n",Get(a));

             }

      }

      

 

}       

 

 

 

五、快排

1、数组排序(快速排序稳定)

 

#include<iostream>

#include<cstring>

#include<cstdio>

#include<cmath>

using namespace std;

 

const int N = 10;

int arr[N];

 

/******************快速排序稳定版本*************************************/

void QuickSort(int low, int high)

{

      if(low >= high)

             return ;

      int i, j, pivot;

      i = low, j = high, pivot =arr[(high + low) >> 1]; //每次取中间元素作为基准

      swap(arr[low], arr[(high +low) >> 1]);

      while(i < j)

      {

             while(i < j&& arr[j] >= pivot) --j;

             arr[i] = arr[j];

             while(i < j&& arr[i] <= pivot) ++i;

             arr[j] = arr[i];

      }

      arr[i] = pivot;

      QuickSort(low, i - 1); //递归左边

      QuickSort(j + 1, high); //递归右边

}

2、快速排序一般版本(可求第K大元素)

int Partition(int low, int high)

{

      int i, j, pivot;

      i = low, j = high, pivot =arr[low];

      while(i < j)

      {

             while(i < j&& arr[j] >= pivot) --j;

             if(i < j)swap(arr[i++], arr[j]);

             while(i < j&& arr[i] <= pivot) ++i;

             if(i < j)swap(arr[i], arr[j--]);

      }

      return j; //返回基准元素位置

}

 

void Quick_Sort(int low, int high)

{

      int pivotpos;

      if(low < high)

      {

             pivotpos =Partition(low, high);

             Quick_Sort(low,pivotpos - 1); //基准左递归排序

             Quick_Sort(pivotpos +1, high); //基准右递归排序

      }

}

 

int select(int low, int high, int k)

{

      int pivotpos, num;

      if(low == high)

             return arr[high];

      pivotpos = Partition(low,high);

      num = pivotpos - low + 1; //左边元素个数

      if(k == num)

             return arr[pivotpos];

      else if(k < num)

             return select(low,pivotpos - 1, k);

      else

             return select(pivotpos+ 1, high, k - num);

}

/*************************************************************************/

 

int main()

{

      int k;

      cout<<"输入10个数字:"<<endl;

      for(int i = 0; i < 10;++i)

             scanf("%d",&arr[i]);

      QuickSort(0, 9);

      cout<<"快速排序后:"<<endl;

      for(int i = 0; i < 10;++i)

             cout<<arr[i]<<"";

      cout<<endl;

      cout<<"输入第K大元素:"<<endl;

      cin>>k;

      cout<<select(0, 9,k)<<endl;

      return 0;

}

 

 

 

3归并排序求逆序数

 

#include <cstdio>  

  

int left[250003], right[250003];  

__int64 count;  

  

void merge(int a[], int l, int m, int r)  

{  

    int i, j, k, n1, n2;  

  

    n1 = m - l + 1;  

    n2 = r - m;  

    for (i = 0; i < n1; i++)  

        left[i] = a[l+i];  

    for (i = 0; i < n2; i++)  

        right[i] = a[m+i+1];  

    left[n1] = right[n2] = 0x7fffffff;  

  

    i = j = 0;  

    for (k = l; k <= r; k++)  

    {  

        if (left[i] <= right[j])  

        {  

            a[k] = left[i++];  

        }  

        else  

        {  

            a[k] = right[j++];  

            count += n1 - i;   

        }  

    }  

}  

  

void mergeSort(int a[], int l, int r)  

{  

    if (l < r)  

    {  

        int m = (l + r) / 2;  

        mergeSort(a, l, m);  

        mergeSort(a, m+1, r);  

        merge(a, l, m, r);  

    }  

}  

  

int main()  

{  

    int n, a[500001];  

  

    while (scanf("%d", &n) && n)  

    {  

        count = 0;  

        for (int i = 0; i < n; i++)  

            scanf("%d", &a[i]);  

        mergeSort(a, 0, n-1);  

        printf("%I64d\n", count);  

    }  

}  
 

 

4、求第k大的数

 

#include<queue>

#include<iostream>

#include<vector>

using namespace std;

struct mycmp

{

    bool operator()(const int &a,const int &b)

    {

        return a>b;

    }

};//这里表示从小到大排列,最小的数在队头,随时准备走出队列

int main()

{

    int n,k,val;

    char str[5];

    int count;

    while(scanf("%d%d",&n,&k)!=EOF)

    {

        priority_queue<int,vector<int>,mycmp> pq;

        while(n--)

        {

            scanf("%s",str);

            if(str[0]=='I')

            {

                scanf("%d",&val);

                pq.push(val);

                while(pq.size()>k)

                    pq.pop();

            }

            else 

            {

                printf("%d\n",pq.top());

            }

        }

    }

    return 0;

}

5、RMQ模板 ,返回区间最值 、 最值的下标

 

#include<string.h>

#include<stdio.h>

#include<math.h>

const int MAX=200005;

int min(int a,int b){return a<b?a:b;}

int dp[MAX][20],a[MAX];

int n,k,val[MAX];

int  LOG[MAX];

void Make_Rmq(int n,int b[])

{

    int i,j;

    for(i=1;i<=n;i++)

        dp[0][i]=b[i];

    for(i=1;i<=LOG[n];i++)

    {

        int limit=n+1-(1<<i);

        for(j=1;j<=limit;j++)

            dp[i][j]=min(dp[i-1][j],dp[i-1][j+(1<<i>>1)]);

    }

}

int RMQ(int l,int r)

{

    int  k=LOG[r-l+1];

    return min(dp[k][l],dp[k][r-(1<<k)+1]);

}

 

void Make_Rmqindex(int n,int b[])

{

    int i,j;

    for(i=1;i<=n;i++)

        dp[0][i]=i;

    for(i=1;i<=LOG[n];i++)

    {

        int limit=n+1-(1<<i);

        for(j=1;j<=limit;j++)

        {

            int x=dp[i-1][j],y=dp[i-1][j+(1<<i>>1)];

            dp[i][j]=b[x]<b[y]?x:y;

        }

    }

}

int Rmq_Index(int l,int r,int b[])

{

    int k=LOG[r-l+1];

    int x=dp[k][l];

    int y=dp[k][r-(1<<k)+1];

    return b[x]<b[y]?x:y;

}

int main()

{

    int t,i,j;

    LOG[0]=-1;

    for(i=1;i<MAX;i++)

        LOG[i]=LOG[i>>1]+1;

    for(i=1;i<=10;i++)

            val[i]=i;

    Make_Rmqindex(10,val);

    int l,r;

    while(1)

    {

        scanf("%d%d",&l,&r);//l<r

        int ans=Rmq_Index(l,r,val);

        printf("%d\n",ans);

    }

    return 0;

}

 

 

6快速幂求余模板

 

经改进后代码如下:(输入a,k,m,a^k%m)

long f(long a,longk,long m) 
{ 
long b=1; 
while(k>=1) 
{ 
if(k%2==1) b=a*b%m; 
a=a*a%m; 
k=k/2; 
} 
return b; 
}

7、最长公共子序列

 

/*

最长公共子序列:输出s1s2的最长公共子序列 不一定连续 如 abcde aafe 则结果为ae   

*/

 

#include <stdio.h>

#include <string.h>

#define MAXLEN 3000//输入的字符串的最大长度

 

char x[MAXLEN];

char y[MAXLEN];

int b[MAXLEN][MAXLEN];//b存的是方向 用来辅助输出最后的公共字串

int c[MAXLEN][MAXLEN];//c[i][j]表示s1i个字符和s2j个字符的最长公共子序列

 

void LCSLength(int n, int m)

{

   int i, j;

   

   for(i = 0; i <= n; i++)

       c[i][0] = 0;

   for(j = 1; j <= m; j++)

       c[0][j] = 0;

   for(i = 1; i<= n; i++)

   {

       for(j = 1; j <= m; j++)

       {

           if(x[i-1] == y[j-1])//2者相等的时候则此时 c[i][j] =c[i-1][j-1] + 1;

           {

               c[i][j] =c[i-1][j-1] + 1;

               b[i][j] = 0;

           }

           else if(c[i-1][j] >=c[i][j-1])//如果不相等 则c[i][j]的值取c[i][j-1],c[i-1][j]中最大的

           {

               c[i][j] =c[i-1][j];

               b[i][j] = 1;

           }

           else

           {

               c[i][j] =c[i][j-1];

               b[i][j] = -1;

           }

       }

   }

}

 

void FindLCS(int i, int j)//递归输出最长公共子序列

{

   if(i == 0 || j == 0)

       return;

   if(b[i][j] == 0)

   {

       FindLCS(i-1,j-1);

       printf("%c",x[i-1]);

   }

   else if(b[i][j] == 1)

       FindLCS(i-1,j);//如果是标记为1 则剩余的未输出字符 从s1的前i-1 s2的前j个中找出来 当递归到标记为0的时候就可以输出了

   else

       FindLCS(i,j-1);

}

 

int main(int argc, char **argv)

{

 

      while(scanf("%s %s",x,y)!=EOF)

      {

   int m,n;

   n = strlen(x);

   m = strlen(y);

   LCSLength(n,m);

   FindLCS(n,m);

      //printf("%d",c[n][m]);//输出公共串的最长的长度

      printf("\n");

      }

   return 0;

}

 

 

8、快速查找素数

 

 

 

#include<stdio.h>

#include<string.h>

#define MAX 2000001

#define MAX_PRIME 2000001

bool nums[MAX];

int prime[MAX_PRIME];

void MakePrime()

{

   int i,j;

   int pl=0;

   nums[0]=1,nums[1]=1;

   memset(prime,true,sizeof(prime));

   for(i=2;i<MAX;i++)

   {

       if(!nums[i])

          prime[pl++]=i;

       for(j=0;j<pl&&i*prime[j]<=MAX;j++)

     {

         nums[i*prime[j]]=1;

         if(!(i%prime[j]))

             break;

      }

   }

}

int main()

{

  int n,j;

  MakePrime();

  while(scanf("%d",&n)!=EOF)

  {

     if(n>1)

     {

        printf("2");

       for(j=1;prime[j]<=n;j++)

       {

           printf("%d",prime[j]);

         }

      }

     printf("\n");

 }

 return 0;

} 

 

 

9、表达式求值

 

/*

3

add(1,2)

max(1,999)

add(min(1,1000),add(100,99))

*/

 

 

#include<cstdio>

#include<iostream>

using namespace std;

char str[1000];

int start;

int val()

{

        intv,n;

        switch(str[start])

        {

        case'm':start+=3;if(str[start-2]=='i') return min(val(),val());else returnmax(val(),val());

        case'a':start+=3;return val()+val();

        case')':

        case'(':

        case',':++start;return val();

        default:sscanf(str+start,"%d%n",&v,&n);start+=n;returnv;

        }

}

int main()

{

        intn;

        scanf("%d",&n);

        while(n--)

        {

                  scanf("%s",str);

                  start=0;

                  printf("%d\n",val());

        }

}       

    

 

七、二分

int binarysearch(int arr[], int n, int key)

{

      int low = 0, high = n;

      while(low < high)

      {

             int mid = low + (high- low) / 2;

             if(arr[mid] == key)

             {

                    cout<<"fad";

                    return mid;

             }

 

 

             else if(arr[mid] >key)

                    high = mid;

             else

                    low = mid + 1;

      }

      return -1;

}

八、最短路径

 

1、最短路径+畅通工程续

每组数据第一行是两个整数NMN<=100M<=10000),

N表示成都的大街上有几个路口,

标号为1的路口是商店所在地,标号为N的路口是赛场所在地,

M则表示在成都有几条路。

N=M=0表示输入结束。

接下来M行,每行包括3个整数ABC1<=A,B<=N,1<=C<=1000,表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。

输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input

N(有几个路口) M(有几条路)

nodenum      edgenum

 

2                1

1 2 3

 

3 3

 

1 2 5

2 3 5

3 1 2

 

0 0

 

Sample Output

3

2

 

SPFA版本:

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<climits>

#include<queue>

#include<algorithm>

using namespace std;

 

#define N 110

#define MAX INT_MAX >> 1

#define CLR(arr, what) memset(arr, what, sizeof(arr))

 

int nodenum, edgenum;

int map[N][N], dis[N];

bool visit[N];

 

int SPFA(int src, int des)

{

   queue<int> q;

   CLR(visit, false);

   for(int i = 1;i <= nodenum;++i)

       dis[i] = MAX;

   dis[src] = 0;

   visit[src] = true;

 

   q.push(src);

   while(!q.empty())

   {

       int cur = q.front();

       q.pop();

       visit[cur] = false; //出队标记为false

       for(int i = 1; i <=nodenum; ++i)

       {

           if(dis[i] > dis[cur]+ map[cur][i]) //没有2个集合,和Dijkstra有本质区别

           {

               dis[i] = dis[cur] +map[cur][i]; //能松弛就松弛

               if(!visit[i]) //不在队列中则加入,然后更新所有以前经过此点的最短路径

               {

                   q.push(i);

                   visit[i] =true;

               }

           }

       }

   }

   return dis[des];

}

 

int main()

{

   int start, end, cost;

   int answer;

   while(~scanf("%d%d",&nodenum, &edgenum) && (nodenum + edgenum))

   {

       for(int i = 1; i <=nodenum; ++i)

           for(int j = 1; j <=nodenum; ++j)

               map[i][j] = MAX;

       for(int i = 0; i <edgenum; ++i)

       {

           scanf("%d%d%d", &start, &end, &cost);

           if(cost <map[start][end])

               map[start][end] =map[end][start] = cost;

       }

       answer = SPFA(1, nodenum);

       printf("%d\n",answer);

   }

   return 0;

}

 

 

 

2、畅通工程再续

 

/*

3(v) 3(e)

 

0 1 1

0 2 3

1 2 1

 

0(sv) 2(ev)

 

城镇分别以0N-1编号

如果不存在从ST的路线,就输出-1.

*/

 

#include<iostream>

#include<stdio.h>

using namespace std;

#define inf 9999999

int map[250][250];

int n,m;

int Floyd(int x,int y)

{

   int t,i,j;

   for(t=0;t<n;t++)

       for(i=0;i<n;i++)

           for(j=0;j<n;j++)

           if(map[i][j]>map[i][t]+map[t][j]) 

           {

               map[i][j]=map[i][t]+map[t][j];

           }

   if(map[x][y]==inf) return -1;

   else return map[x][y];

}

int main()

{

      //n v,m e

   while(scanf("%d%d",&n,&m)!=EOF)

   {

       int a,b,v,d,f,num;

       for(int i=0; i<=n; i++)

           for(int j=0; j<=n;j++)

               map[i][j]=map[j][i]=inf;

       for(inti=0;i<n;i++) //注意同一点的权值为0,刚开始wa在这儿

       map[i][i]=0;

       

       

       for(int i=0; i<m; i++)

       {

           cin>>a>>b>>v;

           if(map[a][b]>v)

               map[a][b]=map[b][a]=v;

       }

       cin>>d>>f;

       num=Floyd(d,f);

       cout<<num<<endl;

   }

   return 0;

}

 

3、公交车最短路径(公交站是英文名字)

输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000)
第二行有徐总的所在地start,他的目的地end
接着有n行,每行有站名s,站名e,以及从se的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)
note
:一组数据中地名数不会超过150个。
如果N==-1,表示输入结束。

 

 

Output

如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。

 

 

Sample Input

6

xiasha westlake

 

xiasha station 60

xiasha ShoppingCenterofHangZhou 30

station westlake 20

ShoppingCenterofHangZhou supermarket10

xiasha supermarket 50

supermarket westlake 10

-1

 

 

#include<iostream>

#include<map>

#include<cstdio>

#include<cstring>

#include<string>

#include<algorithm>

using namespace std;

int dis[155], len[155][155];

bool visit[155];

#define MAX 0x3f3f3f3f

 

void Dijsktra(int start, int end)

{

      int k, temp;

      memset(visit, 0,sizeof(visit));

      for(int i = start; i <=end; ++i)

             dis[i] = (i == start ?0 : MAX); //visit[start] = 1; //如果标记为1,则与temp比较的全都是MAX

      for(int i = start; i <=end; ++i)

      {

             temp = MAX;

             for(int j = start; j<= end; ++j)

                    if(!visit[j]&& dis[j] < temp)

                           temp =dis[k = j];

             visit[k] = 1;

             if(temp == MAX) break;

             for(int j = start; j<= end; ++j)

                    if(dis[j] >dis[k] + len[k][j])

                           dis[j] =dis[k] + len[k][j];

      }

}

 

int main()

{

      int num, iterator, distance,flag;

      char begin[30], end[30];

      char a[30], b[30];

      map<string, int>station;

      while(scanf("%d",&num) != EOF && num != -1)

      {

             station.clear();

             memset(len, MAX,sizeof(len));

             flag = 0;

             scanf("%s%s",begin, end);

             if(strcmp(begin, end)== 0) flag = 1;

             station[begin] = 1;

             station[end] = 2;

             iterator = 3;

             for(int i = 0; i <num; ++i)

             {

                    scanf("%s%s%d",a, b, &distance);

                    if(!station[a])

                           station[a]= iterator++;

                    if(!station[b])

                           station[b]= iterator++;

                           len[station[a]][station[b]]= len[station[b]][station[a]] = distance;

             }

             if(flag)

             {

                    printf("0\n");

                    continue;

             }

             Dijsktra(1, iterator);

             if(dis[2] == MAX)      printf("-1\n");

             elseprintf("%d\n", dis[2]);

      }

      return 0;

}

 


22、最短路径 求最短距离

 


现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

 

Input

Nv)和Me(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0N-1编号。


接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

 

 

Output

对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从ST的路线,就输出-1.

 

 

Sample Input

3 3

0 1 1

0 2 3

1 2 1

0 2

3 1

0 1 1

1 2

 

 

Sample Output

2

-1

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

 

#define N 210

#define MAX 9999999

#define CLR(arr, what) memset(arr,what, sizeof(arr))

 

int num, road;

int dis[N], maze[N][N];

bool visit[N];

 

void Dijkstra(int start)

{

      inttemp, k;

      CLR(visit,false);

      for(inti = 0; i < num; ++i)

             dis[i]= (i == start ? 0 : maze[start][i]);

      visit[start]= true;

      for(inti = 0; i < num; ++i)

      {

             temp= MAX;

             for(intj = 0; j < num; ++j)

                    if(!visit[j]&& temp > dis[j])

                           temp= dis[k = j];

             if(temp== MAX)

                    break;

             visit[k]= true;

             for(intj = 0; j < num; ++j)

                    if(!visit[j]&& dis[j] > dis[k] + maze[k][j])

                           dis[j]= dis[k] + maze[k][j];

      }

}

 

int main()

{

   int a, b, cost, start, end;

   while(scanf("%d%d", &num, &road) != EOF)

   {

       for(int i = 0; i < N; ++i)

                    for(intj = 0; j < N; ++j)

                           maze[i][j]= MAX;

       for(int i = 0; i < road; ++i)

       {

           scanf("%d%d%d", &a,&b, &cost);

           if(cost < maze[a][b]) //一条路可以有多个cost,记录最小的。注意

           maze[a][b] = maze[b][a] = cost;

       }

       scanf("%d%d", &start,&end);

       Dijkstra(start);

       if(dis[end] == MAX)

                    printf("-1\n");

       else

                    printf("%d\n",dis[end]);

   }

   return 0;

}

 

 

4、单源最短路Dijkstra算法。只不过起点给你多个,然后求可以到达的目的地中路径最短的一条

 

 66条路) 2(和草家相邻城市个数) 3(想去城市的个数)

1 3 5

1 4 7

2 8 12

3 8 4

4 9 12

9 10 2

1 2(和草家相邻)

8 9 10(想去)

 

 

输出草儿能去某个喜欢的城市的最短时间

 

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

#include<algorithm>

usingnamespace std;

#defineMAX 0x3f3f3f3f

introad, link, want, total;

intmap[1010][1010], linkarr[1010], wantarr[1010], dis[1010];

boolvisit[1010];

 

voidDijkstra(int start)

{

   int temp, k;

   memset(visit, 0, sizeof(visit));

   for(int i = 1; i <= total; ++i)

       dis[i] = map[start][i];

   dis[start] = 0;

   visit[start] = 1;

   for(int i = 1; i <= total; ++i)

   {

       temp = MAX;

       for(int j = 1; j <= total; ++j)

           if(!visit[j] && temp >dis[j])

               temp = dis[k = j];

       visit[k] = 1;

       for(int j = 1; j <= total; ++j)

           if(!visit[j] && dis[j] >dis[k] + map[k][j])

               dis[j] = dis[k] + map[k][j];

   }

}

 

intmain()

{

   int x, y, cost, minn, answer;

   while(scanf("%d%d%d", &road,&link, &want) != EOF)

   {

       total = 0;

       memset(map, MAX, sizeof(map));

       for(int i = 1; i <= road; ++i)

       {

           scanf("%d%d%d", &x,&y, &cost);

           if(cost < map[x][y])

               map[x][y] = map[y][x] = cost;

           total = max(total, max(x, y)); //错了N久。。。。因为没有给出点的个数。

       }

       for(int i = 1; i <= link; ++i) //相连的城市

           scanf("%d",&linkarr[i]);

       for(int i = 1; i <= want; ++i) //目的地

           scanf("%d", &wantarr[i]);

       answer = MAX;

       for(int i = 1; i <= link; ++i)//linkarr数组中所有元素中到达目的地最短的路

       {

           Dijkstra(linkarr[i]);

           minn = MAX;

           for(int j = 1; j <= want; ++j)//linkarr[i]中可以到达的目的地中最短

               if(dis[wantarr[j]] < minn)

                   minn = dis[wantarr[j]];

           if(answer > minn)

               answer = minn;

       }

       printf("%d\n", answer);

   }

   return 0;

}

 

 

 

5、飘谊想知道他走完观光道路并回到源点的最短路径

V e

4 5

1 2 3

2 3 4

3 4 5

1 4 10

1 3 12

 

#include <stdio.h>

#include <string.h>

#define Maxsize 20

#define FindMin(a,b) a>b?b:a

#define INF 999999999

int g[Maxsize][Maxsize];

int degree[Maxsize];

int count;

int v[Maxsize];

int ans;

int T;

void dfs(int u,int value)

{

      int i,j;

      if(u==T)

      {

             ans=FindMin(value,ans);

//         printf("%d%d\n",value);

      }

      for(i=0;i<count;i++)

      {

             if(!((u>>i)&1))

             {

                    for(j=i+1;j<count;j++)

                           if(!((u>>j)&1))

                           {

                                  intnext=u;

                                  next=next|(1<<i);

                                  next=next|(1<<j);

                                  dfs(next,value+g[v[i]][v[j]]);

                           }

             }

      }

}

int main()

{

      int n,m;

      int u,e,l;

      int i,j,k;

      int sum=0;

      while(~scanf("%d%d",&n,&m))

      {

             memset(degree,0,sizeof(degree));

             for(i=0;i<=n;i++)

                    for(j=0;j<=n;j++)

                           g[i][j]=INF;

             sum=0;

             while(m--)

             {

                    scanf("%d%d%d",&u,&e,&l);

                    sum+=l;

                    degree[u]++;degree[e]++;

                    g[u][e]=g[e][u]=FindMin(g[u][e],l);

             }

             for(k=1;k<=n;k++)

                    for(i=1;i<=n;i++)

                           for(j=1;j<=n;j++)

                                  g[i][j]=FindMin(g[i][j],g[i][k]+g[k][j]);

             count=0;

             for(i=1;i<=n;i++)

                    if(degree[i]&1)

                           v[count++]=i;

             T=0;

             for(i=0;i<count;i++)

             {

                    T=(T<<1)|1;

             }

             ans=INF;

             dfs(0,0);

             

             printf("%d\n",sum+ans);

      }

      return 0;

}  

 

 

6、给多个坐标,求最短路径的最大边

2

0 0(起点)

3 4(终点)

 

3

 

17 4

19 4

18 5

 

0

Sample Output

Scenario #1

Frog Distance = 5.000

 

Scenario #2

Frog Distance = 1.414

 

#include<iostream>

#include<cstdlib>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

using namespace std;

pair<int ,int> a[200];           //保存n个石头的坐标

double lowcost[200],closet[200];//Prim算法必备,lowcost[i]表示i距离集合的最近距离,closet[i]表示i距离集合最近的点

double map[200][200];           //两点之间的距离

int main()

{

   int n;

   int k=1;

   while(cin>>n,n)

   {

       int i,j;

       for (i = 0 ;i < n ; i++ )

           cin>>a[i].first>>a[i].second;   //输入n个点的坐标,从0开始,也就是说题目编程求0-1的最小Frog Distance

       memset(lowcost,0,sizeof(lowcost));   //清零

       for ( i = 0 ; i < n ; i ++ )

       {

           for ( j = 0 ; j < n ; j ++ )

           {//求任意两点的距离,保存到map

               map[i][j]=1.0*sqrt(pow(1.0*abs(a[i].first-a[j].first),2)+pow(1.0*abs(a[i].second-a[j].second),2));

           }

       }

       double ans=0.0;//所要求的答案,初始化为0

       for ( i = 0 ; i< n ; i++ )

       {//0放入集合,则点到集合的距离此时是点到0的距离

           lowcost[i]=map[0][i];

           closet[i]=0;

       }

 

       for ( i = 0 ; i < n - 1 ; i ++ )

       {

           doublemindis=1.0*(1<<20);       //点到集合最小距离,初始化为最大

           int minone;                       //到集合最小距离对应的点

           for ( j = 0 ; j < n ; j ++ )

           {

               if(lowcost[j]&&mindis>lowcost[j])

               {//j点不在集合中,并且j到集合的距离比最小距离还小,则更新最小距离

                   mindis=lowcost[j];

                   minone=j;

               }

           }

           if(ans<mindis)       //如果答案并不比更新的最小距离大

               ans=mindis;       //更新答案

           lowcost[minone]=0.0;//将该点入集合

           if(minone==1)       //如果改点是1,则水明义江找到了答案

               break;

           for ( j = 0 ; j < n ; j ++ )

           {//更新各点到集合的最小距离

               if(map[j][minone]<lowcost[j])

               {//如果minone到某点j的距离比原来的j到集合的距离要小,则更新该点到集合的距离为改点到minone的距离

                   lowcost[j]=map[j][minone];

                   closet[j]=minone;

               }

           }

       }

       cout<<"Scenario #"<<k<<endl;

       printf("Frog Distance = %.3f\n\n",ans);

       k++;

   }

   return 0;

}

 

7、最k短路

2v 2e

1 2 5

2 1 4

 

1s 2end 2k

 

#include <cstring>

#include <cstdio>

#include <queue>

#define MAXN 1005

#define MAXM 500005

#define INF 1000000000

using namespace std;

struct node

{

   int v, w, next;

}

edge[MAXM], revedge[MAXM];

struct A

{

   int f, g, v;

   bool operator <(const A a)

   const

   {

       if(a.f == f) return a.g < g;

       return a.f < f;

   }

};

int e, vis[MAXN], d[MAXN], q[MAXM *5];

int

head[MAXN], revhead[MAXN];

int n, m, s, t, k;

void init()

{

   e = 0;

   memset(head, -1, sizeof(head));

   memset(revhead, -1, sizeof(revhead));

}

void insert(int x, int y, int w)

{

   edge[e].v = y;

   edge[e].w = w;

   edge[e].next = head[x];

   head[x] = e;

   revedge[e].v = x;

   revedge[e].w = w;

   revedge[e].next =revhead[y];

   revhead[y] = e++;

}

void spfa(int src)

{

   for(int i = 1; i <= n; i++) d[i] = INF;

   memset(vis, 0, sizeof(vis));

   vis[src] = 0;

   int h = 0, t = 1;

   q[0] = src;

   d[src] = 0;

   while(h < t)

   {

       int u =

           q[h++];

       vis[u] = 0;

       for(int i = revhead[u] ; i != -1; i = revedge[i].next)

       {

           int v = revedge[i].v;

           int w = revedge[i].w;

           if(d[v] > d[u] + w)

           {

               d[v] = d[u] + w;

               if(!vis[v])

               {

                   q[t++] = v;

                   vis[v] = 1;

               }

           }

       }

   }

}

int Astar(int src, int des)

{

   int cnt = 0;

   priority_queue<A>Q;

   if(src == des) k++;

   if(d[src] == INF) return -1;

   A t, tt;

   t.v = src, t.g = 0, t.f = t.g + d[src];

   Q.push(t);

   while(!Q.empty())

   {

       tt = Q.top();

       Q.pop();

       if(tt.v == des)

       {

           cnt++;

           if(cnt == k) return tt.g;

       }

       for(int i = head[tt.v]; i != -1; i = edge[i].next)

       {

           t.v = edge[i].v;

           t.g = tt.g + edge[i].w;

           t.f = t.g + d[t.v];

           Q.push(t);

       }

   }

   return -1;

}

int main()

{

   int x, y, w;

   while(scanf("%d%d", &n, &m) != EOF)

   {

       init();

       for(int i = 1; i <= m; i++)

       {

           scanf("%d%d%d", &x,&y, &w);

           insert(x, y, w);

       }

       scanf("%d%d%d", &s, &t, &k);

       spfa(t);

       printf("%d\n", Astar(s, t));

   }

   return 0;

}

 

 

/*

8、一棵树上的任意两点的距离

7 6

1 6 13 E

6 3 9 E

3 5 7 S

4 1 3 N

2 4 20 W

4 7 2 S

 

3

1 6

1 4

2 6

Sample Output

 

13

3

36

 

*/

 

#include<string.h>

#include<stdio.h>

#include<vector>

#include<math.h>

using namespace std;

const int M =40100;

const double inf = 1e20;

int min(int a,int b){return a<b?a:b;}

int n,k,tdfn,tot;

int dp[20][2*M],vis[M];

int B[2*M],LOG[2*M],used[M],F[2*M],pos[M];

vector<pair<int,int> > edge[2*M];

void rmq_init(int n,int num[])

{

   inti,j;

   for(j=1;j<=n;j++)

       dp[0][j]=num[j];

   for(j=1;j<=LOG[n];j++)

   {

       int limit=n+1-(1<<j);

       for(i=1;i<=limit;i++)

       {

           int x=i+(1<<j>>1);

           dp[j][i]=min(dp[j-1][x],dp[j-1][i]);

       }

   }

}

int rmq(int l,int r,int num[])

{

   intm=LOG[r-l+1];

   return min(dp[m][l],dp[m][r-(1<<m)+1]);

}

int sum[M];

void dfs(int s)

{

   inti,t;

   used[s]=1;

   inttmp=++tdfn;

   B[++tot]=tmp;F[tmp]=s;

   pos[s]=tot;

   for(i=0;i<edge[s].size();i++)

   {

       t=edge[s][i].first;

       if(used[t]) continue;

       sum[t]=sum[s]+edge[s][i].second;

       dfs(t);

       B[++tot]=tmp;//backtrack

   }

}

int lca(int a,int b)

{

   if(pos[a]>pos[b]) swap(a,b);

   intans=rmq(pos[a],pos[b],B);

   return F[ans];

}

int main()

{

   int i,n,m,a,b,w;

   LOG[0]=-1;

   for(i=1;i<2*M;i++) LOG[i]=LOG[i>>1]+1;

   while(scanf("%d%d",&n,&m)!=EOF)

   {

       for(i=0;i<=n;i++) edge[i].clear();

       char str[5];

       for(i=0;i<m;i++)

       {

           scanf("%d%d%d%s",&a,&b,&w,str);

           edge[a].push_back(make_pair(b,w));

           edge[b].push_back(make_pair(a,w));

       }

       sum[1]=0;

       tdfn=0;

       tot=0;

       memset(used,0,sizeof(used));

       dfs(1);

       rmq_init(tot,B);

       scanf("%d",&k);

       while(k--)

       {

           scanf("%d%d",&a,&b);

           printf("%d\n",sum[a]+sum[b]-2*sum[lca(a,b)]);

       }

   }

   return 0;

}

 

 

9、最短路径spfa

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<climits>

#include<queue>

#include<algorithm>

using namespace std;

 

#define N 110

#define MAX INT_MAX >> 1

#define CLR(arr, what) memset(arr, what,sizeof(arr))

 

int nodenum, edgenum;

int map[N][N], dis[N];

bool visit[N];

 

int SPFA(int src, int des)

{

   queue<int> q;

   CLR(visit, false);

   for(int i = 1;i <= nodenum; ++i)

       dis[i] = MAX;

   dis[src] = 0;

   visit[src] = true;

 

   q.push(src);

   while(!q.empty())

   {

       int cur = q.front();

       q.pop();

       visit[cur] = false; //出队标记为false

       for(int i = 1; i <= nodenum; ++i)

       {

           if(dis[i] > dis[cur] + map[cur][i]) //没有2个集合,和Dijkstra有本质区别

           {

               dis[i] = dis[cur] +map[cur][i]; //能松弛就松弛

               if(!visit[i]) //不在队列中则加入,然后更新所有以前经过此点的最短路径

               {

                   q.push(i);

                   visit[i] = true;

               }

           }

       }

   }

   return dis[des];

}

 

int main()

{

   intstart, end, cost;

   intanswer;

   while(~scanf("%d%d", &nodenum,&edgenum) && (nodenum + edgenum))

   {

       for(int i = 1; i <= nodenum; ++i)

           for(int j = 1; j <= nodenum; ++j)

               map[i][j] = MAX;

       for(int i = 0; i < edgenum; ++i)

       {

           scanf("%d%d%d", &start, &end, &cost);

           if(cost < map[start][end])

               map[start][end] =map[end][start] = cost;

       }

       answer = SPFA(1, nodenum);

       printf("%d\n", answer);

   }

   return 0;

}

 

10aij矩阵类型的单源最短路径并且输出最短权值和最短路径

 

/*

起点终点不用tax

5(v)

aij(ij)

 

0 3 22 -1 4

3 0 5 -1 -1

22 5 0 9 20

-1 -1 9 0 4

4 -1 20 4 0

各自的tax

5 17 8 3 1

 

1 3

3 5

2 4

-1 -1

0

 

 

*/

 

 

 

 

#include"stdio.h"

#include"string.h"

 

 

int n;

int tax[111];

int map[111][111];

int path[111][111];

 

 

void floyd()

{

      inttemp;

      intk,i,l;

 

 

      for(i=1;i<=n;i++)

      for(l=1;l<=n;l++)

             path[i][l]=l;

 

 

      for(k=1;k<=n;k++)

      {

             for(i=1;i<=n;i++)

             {

                    for(l=1;l<=n;l++)

                    {

                           temp=map[i][k]+map[k][l]+tax[k];

                           if(temp<map[i][l])

                           {

                                  map[i][l]=temp;

                                  path[i][l]=path[i][k];

                           }

                           elseif(temp==map[i][l])

                           {

                                  if(path[i][l]>path[i][k])

                                         path[i][l]=path[i][k];

                           }

                    }

             }

      }

}

 

 

int main()

{

      inti,l;

      inttemp;

      ints,e;

 

 

      while(scanf("%d",&n),n)

      {

             for(i=1;i<=n;i++)

             for(l=1;l<=n;l++)

             {

                    scanf("%d",&temp);

                    if(temp==-1)map[i][l]=11111111;

                    else              map[i][l]=temp;

             }

 

 

             for(i=1;i<=n;i++)scanf("%d",&tax[i]);

 

 

             floyd();

 

 

             while(scanf("%d%d",&s,&e)!=-1)

             {

                    if(s==-1&& e==-1)   break;

                    printf("From%d to %d :\n",s,e);

                    printf("Path:%d",s);

                    temp=s;

                    while(temp!=e)

                    {

                           printf("-->%d",path[temp][e]);

                           temp=path[temp][e];

                    }

                    printf("\n");

                    printf("Totalcost : %d\n\n",map[s][e]);

             }