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



一、最小生成树...............................................................................................................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);//如果是标记为则剩余的未输出字符 从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]);

             }

      }

      return0;

}

 

 

 

 

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

 

 

/*

 

5 7

1 2 10

1 4 30

1 5 100

2 3 50

3 5 10

4 3 20

4 5 60

60

 

 

*/

 

 

 

#include <iostream>

#include<cstdio>

 

using namespace std;

 

#define MAX 9999999

 

#define LEN 210

 

int map[LEN][LEN]; //某点到某点两点间的的距离

int dist[LEN]; //记录当前点到源点的最短路径长度

int mark[LEN]; //加入进来的点的集合

 

 

 

   //初始化map为正无穷大

   void init()

   {

      int i,j;

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

    {

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

            {

                    map[i][j]=MAX;

             }

      }

   }

 

   //n:多少条路 start:起始点

   //dist[i],最后存储着starti点的最短距离

   void myDijstra(int n,int start)

   {

      int i,j,min,pos;

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

    {

           mark[i]=0;//没有点加入

           dist[i]=map[start][i];//start附近点 dis[]初始化

      }

 

      mark[start]=1;//把起始点加进来

      dist[start]=0;

 

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

    {

 

             min=MAX;

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

            {

                    if(!mark[j] &&dist[j]<min)

                    { //取出不在mark里的最小的dist[i]

                        min=dist[j];

                        pos=j;//标记

                    }

 

             }

               

            if(min==MAX)//已经不能通了

                 break;

 

               mark[pos]=1;//K加进来

 

             //做松弛操作

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

            {

                   if(!mark[j] &&dist[j]>dist[pos]+map[pos][j])//start->j or start->pos,pos->j

                   {

                      dist[j]=dist[pos]+map[pos][j];//这步跟prim算法有点不同

                   }

             }

       }

   }

 

 

 

int main(){

 

      int i,n,line;

 

      int a,b,d;

      scanf("%d%d",&n,&line);//输入点和

      init();

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

           {

      

                scanf("%d%d%d",&a,&b,&d); //输入各边的权值

                  // 这个判断是防止重边的,因为也许会对同一条路给出两个值,这时就保存较小的值

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

                  {

                  map[a][b]=map[b][a]=d;

                  }

             }

 

      myDijstra(n,1);//调用方法(点数,起始点)

 

      //输出15的最短路径

 

      cout<<dist[5]<<endl;

 

      return 0;

 

}

 

 

 

 

九、最大流

1、简单最大流

 2

 V e

3 2

1 2 1

2 3 1

3 3

1 2 1

2 3 1

1 3 1

 

 

 

#include<iostream>

#include<cstring>

#include<cstdio>

#include<cmath>

#include<queue>

#include<algorithm>

using namespace std;

 

#define N 100

#define MAX 1<<28

 

int cost[N][N];

int flow[N], pre[N];

bool visit[N];

int n, m;

 

int BFS()

{

      int temp;

      queue<int> q;

      visit[1] = true;

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

      memset(visit, false,sizeof(visit));

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

             flow[i] = MAX;

      q.push(1);

      while(!q.empty())

      {

             temp = q.front();

             q.pop();

             if(temp == n)

                    break;

             for(int i = 1; i <=n; ++i) //寻找增广路最小流量

             {

                    if(!visit[i]&& cost[temp][i] > 0)

                    {

                           visit[i]= true;

                           flow[i]= min(flow[temp], cost[temp][i]);

                           pre[i] =temp; //更新路径

                           q.push(i);

                    }

             }

      }

      if(!visit[n] || n == 1) //找不到完整增广路or源点汇点重合

             return -1;

      else

             return flow[n];

}

 

int EK()

{

      int temp, d, res, maxflow;

      maxflow = 0;

      while( (d = BFS() ) != -1)

      {

             maxflow += d;

             temp = n;

             while(temp != 1)

             {

                    res =pre[temp];

                    cost[res][temp]-= d; //正向边

                    cost[temp][res]+= d; //反向边

                    temp = res;

             }

      }

      return maxflow;

}

 

int main()

{

      int ncase, T = 1;

      int start, end, capacity;

      scanf("%d",&ncase);

      while(ncase--)

      {

             memset(cost, 0,sizeof(cost));

       // v e

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

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

             {

                    scanf("%d%d%d",&start, &end, &capacity); //重边叠加

                    cost[start][end]+= capacity;

             }

             printf("Case %d:%d\n", T++, EK());

      }

      return 0;

}

 

 

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

 

/*

 

从自己的房子出发到农场,再从农场返回自己的房子,要求去回不走同一条路。

房子的点数为1,农场为n,在1n之间有很多点,给出n个顶点,m条边,然后m行每行有三个数,

abc代表ac的路径长度为c,并且ab是无向边,

 

现在要求从1点到n点在从n点返回1点的最短路

 

4v(n) 5e(m)

 

a b c

1 2 1

2 3 1

3 4 1

1 3 2

2 4 2

*/

/*

Memory 968K

Time   0MS

*/

#include <iostream>

#include <queue>

using namespace std;

#define INF INT_MAX

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

#define MAXV 1100

#define MAXM 40100

 

typedef struct{

      int s,t,next,w,r;

}Edge;

 

Edge edge[MAXM];

int source,sink,n,m,mincost,edgesum;

int head[MAXV],d[MAXV],parent[MAXV];

 

void addedge(int a,int b,int c,int r){

      edge[edgesum].s=a;

      edge[edgesum].t=b;

      edge[edgesum].r=r;

      edge[edgesum].w=c;

      edge[edgesum].next=head[a];

      head[a]=edgesum++;

 

      edge[edgesum].s=b;

      edge[edgesum].t=a;

      edge[edgesum].r=0;

      edge[edgesum].w=-c;

      edge[edgesum].next=head[b];

      head[b]=edgesum++;

}

 

int spfa(){

      queue <int>q;

      int v,i,tmp;

      bool vis[MAXV];

      

      for(i=0;i<=sink;i++)d[i]=INF;

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

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

 

      q.push(source);

      vis[source]=true;

      d[source]=0;

      while(!q.empty()){

             v=q.front();q.pop();

             vis[v]=false;

 

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

                    tmp=edge[i].t;

                    if(edge[i].r&& edge[i].w+d[v]<d[tmp]){

                           d[tmp]=edge[i].w+d[v];

                           parent[tmp]=i;

                           if(!vis[tmp]){

                                  q.push(tmp);

                                  vis[tmp]=true;

                           }

                    }

             }

      }

      return 0;

}

 

void MCMF(){

      int u;

      mincost=0;

      while(1){

             spfa();

             if(parent[sink]==-1)break;

 

             u=parent[sink];        //这里不用求出增光路径上的最小流量

       while(u!=-1){             //因为最小流量一定为1

                    edge[u].r--;

                    edge[u^1].r++;

           u=parent[edge[u].s];

       }

       mincost+=d[sink];

      }

}

 

int main(){

      int i,a,b,c;

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

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

             edgesum=0,source=0,sink=n+1;

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

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

                    addedge(a,b,c,1);

                    addedge(b,a,c,1);

             }

             addedge(source,1,0,2);

             addedge(n,sink,0,2);

 

             MCMF();

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

      }

      return 0;

}

 

 

十二、贪心问题

4、拦截导弹

 

#include<stdio.h>

#include<string.h>

int main()

{

              intt,n,i,j,maxdp;

              scanf("%d",&t);

              while(t--)

              {

                              intdp[25]={0},a[25]={0},b[25]={0};

                              scanf("%d",&n);

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

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

                              for(i=0,j=n-1;i<n&&j>=0;++i,--j)

                      b[i]=a[j];

                              maxdp=0;

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

                              {

                         dp[i]=1;

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

                                             {

               if(b[i]>b[j]&&dp[i]<dp[j]+1)

                                                                           dp[i]=dp[j]+1;

                                             }

                                             if(maxdp<dp[i])

                                                                           maxdp=dp[i];

                              }

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

              }

              return0;

}                       

 

5、最少拦截系统

#include<iostream>

using namespace std;

int main()

{ 

   int n,i,j,a;

   int sum[10002];

   while(cin>>n)

   {

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

           sum[i]=400000;

         //8 389 207 155 300 299 170 158 65 

 

 

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

       {

           cin>>a;

           j=0;

           while(sum[j]<a)

           {

               j++;

           }

           sum[j]=a;

       }

       int total=0;

       

       

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

           if(sum[i]<400000)

               total++;

           cout<<total<<endl;

   }

   return 0;

}

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

5、心急的c小佳

 

 

if you have five sticks whose pairs oflength and weight are ( 9 , 4 ) , ( 2 , 5 ) , ( 1 , 2 ) , ( 5 , 3 ) , and ( 4 ,1 ) ,

then the minimum setup time should be 2minutes since there is a sequence of pairs ( 4 , 1 ) , ( 5 , 3 ) , ( 9 , 4 ) ,( 1 , 2 ) , ( 2 , 5 ) .

 

 

 

Sample Input

 

3

5

4 9 5 2 2 1 3 5 1 4

3

2 2 1 1 2 2

3

1 3 2 2 3 1

 

Sample Output

 

2

1

3

 

 

 

 

#include<iostream>

#include<algorithm>

#include<cstring>

using namespace std;

struct point{

              intstart,end;

              intvisit;

};

bool cmp(point x,point y)

{

              returnx.start<y.start;

}

int main()

{

              pointa[5005];

              intt,n,i,j,count;

              cin>>t;

              while(t--)

              {

                              memset(a,0,sizeof(a));

                              count=0;

                              j=0;

                              intkstart,kend;

                              cin>>n;

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

                              {

                                             cin>>a[i].start;

                                             cin>>a[i].end;

                                             a[i].visit=1;

                              }

                              sort(a,a+n,cmp);

                              while(count<n)

                              {

                                             kstart=-1;kend=-1;

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

                                             {

                                                            if(a[i].start>=kstart&&a[i].end>=kend&&a[i].visit)//并且没访问过

                                                            {

                                                                           count++;

                                                                           a[i].visit=0;

                                                                           kstart=a[i].start;

                                                                           kend=a[i].end;

                                                            }

                                             }

                                             j++;

                              }

                              cout<<j<<endl;

 

                              

              }

              return0;

}

 

点评:上面两个题做法是一致的,都是进行标记,进行暴力搜索,很好的贪心的题。

7radar

/*

题意:给定点集S={xiyii=1.2.3...n},求用圆心在x轴上,半径为r的圆覆盖S所需的圆的最少个数。

解题思路:先把给定的xiyi,r转化为x轴上的区间,即圆心所在的区间,这样就转化为了区间选点问题。

先对右端点从小到大排序,右端点相同时,左端点从小到大排序。

*/

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

struct radar{

              doublea,b;

}r[1005];

bool comp(radar a1,radar a2)

{

              if(a1.b!=a2.b)//对右端点从小到大排序

              returna1.b<a2.b;

              returna1.a<a2.a;//右端点相同,左端点从小到大排序

}

int main()

{

              intn,d,i,cas=0;

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

              {

                              doublex,y;

                              intflag=0,m=0;

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

                              {

                                             scanf("%lf%lf",&x,&y);

                                             if(fabs(y)>d)

                                             {

                                                            flag=1;//高度大于半径,有覆盖不到的点           

                                                            continue;

                                             }

                                             doublediff=sqrt(d*d-y*y);

                                              r[m].a=x-diff;

                                              r[m++].b=x+diff;

                              }

                              printf("Case%d: ",++cas);

                              if(flag)

                              {

                                             printf("-1\n");

                                             continue;

                              }

                              sort(r,r+m,comp);

                              intcnt=1,p=0;

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

                              {

                                             if(r[i].a<=r[p].b)

                                             {

                                                            continue;

                                                            //区间重叠,不换 雷达

                                             }

                                             else{

                                                            cnt++;

                                                            p=i;

                                             }

                              }

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

              }

              return0;

}

 

 

十三、几何问题

1、点线距离

inline double PPdis(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline double PLdis(Point a,Point l1,Point l2){
    return fabs(Cross(a,l1,l2)/PPdis(l1,l2));
}

2、是否是凸多边形

inline int _sgn(double x){return fabs(x) < eps ? 0 : (x > 0 ? 1 : 2);}int is_convex(int n,Point P[]){//允许相邻边共线,顶点按顺时针或者逆时针给出
    int i,s[3]={1,1,1};
    for(i=0;i<n&&s[1]|s[2];i++)
        s[_sgn(Cross(P[i],P[(i+1)%n],P[(i+2)%n]))]=0;
    return s[1]|s[2];
}

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

int inside_convex(Point q,int n,Point *p){
    int i,s[3]={1,1,1};
    for(i=0;i<n&&s[1]|s[2];i++)
        s[_sgn(Cross(p[i],p[(i+1)%n],q))]=0;
    return s[1]|s[2];
}

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

 

#include <math.h>
#include <cstdio>
#include<algorithm>using namespace std;const  int maxn = 100010;const double eps = 1e-8;
inline double sgn(double x) {return fabs(x)<eps?0:(x>0?1:-1);}struct point{
    double x,y;
    bool operator == (const point& t) const {
        return sgn(x-t.x)==0 && sgn(y-t.y)==0;
    }
}p[maxn],set[maxn];
inline double cross(point a,point b,point c){return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);}bool dotOnSeg(point p, point s, point e) {                
    if ( p == s || p == e )     return true;
    return sgn(cross(s,e,p))==0 && sgn((p.x-s.x)*(p.x-e.x))<=0 && sgn((p.y-s.y)*(p.y-e.y))<=0;
} bool point_in_polygon(point o, point* p, int n) {
    int i, t;
    point a, b;
    p[n] = p[0];    t = 0;
    for (i=0; i < n; i++) {
        if ( dotOnSeg(o, p[i], p[i+1]) )        return true;
        a = p[i]; b = p[i+1];
        if ( a.y > b.y ) {
            point tmp = a; a = b; b = tmp;
        }
        if ( cross(o, a, b) < -eps && a.y < o.y-eps && o.y < b.y+eps )
            t++;
    }
    return t&1;
}
 
 

十四、kmp算法

1、最小的匹配位置

 

/*

a[1], a[2], ...... , a[N]

b[1], b[2], ...... , b[M]

存在k使得: a[K] = b[1], a[K + 1] = b[2], ...... ,a[K + M - 1] = b[M]

If there are more than one K exist, output the smallest one.

 

2(组数)

13 5

1 2 1 2 3 1 2 3 1 3 2 1 2

1 2 3 1 3

*/

 

#include<cstdio>

#include<cstring>

int n,m;

int a[1000010],b[10010];

int p[11111];

void getp(){

   p[1]=0;

   int i,j=0;

   for(i=2;i<=m;i++){

       while(j>0&&b[j+1]!=b[i]) j=p[j];

       if(b[j+1]==b[i]) j+=1;

       p[i]=j;

   }

}

int kmp()

{

   int i,j=0,cnt=0;

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

       while(j>0&&b[j+1]!=a[i]) j=p[j];

       if(b[j+1]==a[i]) j+=1;

       if(j==m){

           return i-j+1;

           j=p[j];

 

       }

   }

   return -1;

}

int main()

{

   int t;

   scanf("%d",&t);

   while(t--)

   {

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

       for(int i=1;i<=n;i++)scanf("%d",&a[i]);

       for(intj=1;j<=m;j++) scanf("%d",&b[j]);

       getp();

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

   }

}

 

2、子串出现的次数

 

 

/*

 

1组数

 

AZA            w

AZAZAZA        T

 

3

on a single line: the number of occurrences of the word W in the text T.

*/

 

 

#include<cstdio>

#include<cstring>

int n,m;

char a[1000010],b[10010];

int p[11111];

void getp(){

   p[1]=0;

   int i,j=0;

   for(i=2;i<=m;i++){

       while(j>0&&b[j+1]!=b[i]) j=p[j];

       if(b[j+1]==b[i]) j+=1;

       p[i]=j;

   }

}

int kmp()

{

   int i,j=0,cnt=0;

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

       while(j>0&&b[j+1]!=a[i]) j=p[j];

       if(b[j+1]==a[i]) j+=1;

       if(j==m){

            cnt++;

           j=p[j];

 

       }

   }

   return cnt;

}

int main()

{

   int t;

   scanf("%d",&t);

   while(t--)

   {

       scanf("%s%s",b+1,a+1);

       m=strlen(b+1);

       n=strlen(a+1);

       getp();

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

   }

}

 

 3、简单求周期

/*

abcd

aaaa

ababab

 

1

4

3

 

*/

 

#include<cstdio>

#include<cstring>

char b[1000010];

int p[1000010];

int m,n;

void getp(){

   p[1]=0;

   int i,j=0;

   for(i=2;i<=m;i++){

       while(j>0&&b[j+1]!=b[i]) j=p[j];

       if(b[j+1]==b[i]) j+=1;

       p[i]=j;

   }

}

int main(){

  while(scanf("%s",b+1)!=EOF)

  {

      if(b[1]=='.') break;

      m=strlen(b+1);

      getp();

      if(m%(m-p[m])==0)printf("%d\n",m/(m-p[m]));

      elseprintf("1\n");

  }

}

 

 

 

 

/*

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

3

3

CATCATCATCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

ACATCATCATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AACATCATCATTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

 

*/

 

#include<cstdio>

#include<cstring>

char str[20][70];

char tmp[70];

int p[70];

void getp(int m,char *b1){

   char b[70];

   strcpy(b+1,b1);

   p[1]=0;

   int i,j=0;

   for(i=2;i<=m;i++){

       while(j>0&&b[j+1]!=b[i]) j=p[j];

       if(b[j+1]==b[i]) j+=1;

       p[i]=j;

   }

}

bool kmp(char *a1,char *b1,int n,int m)

{

   char a[70],b[70];

   strcpy(a+1,a1);strcpy(b+1,b1);

   int i,j=0,cnt=0;

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

       while(j>0&&b[j+1]!=a[i]) j=p[j];

       if(b[j+1]==a[i]) j+=1;

       if(j==m){

            return true;

       }

   }

   return false;

}

bool check(char *s,int tot)

{

    int i,j;

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

    {

        intn=strlen(str[i]+1),m=strlen(s);

        if(!kmp(str[i]+1,s,n,m))

            return false;

    }

    return true;

}

char ans[70];

int main()

{

   int t,n,i,j;

   scanf("%d",&t);

   while(t--)

   {

       scanf("%d",&n);

       for(i=1;i<=n;i++)  scanf("%s",str[i]+1);

       int len=strlen(str[1]+1);

       int L=0;

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

       {

           for(j=1;j<=len-i+1;j++)

           {

               strncpy(tmp,str[1]+j,i);

               memset(p,0,sizeof(p));

               getp(i,tmp);

               if(check(tmp,n))

               {           

                   if(i>=L)

                   {

                   if(strcmp(tmp,ans)<0&&i==L) strcpy(ans,tmp);

                   if(i>L)  strcpy(ans,tmp);

                      L=strlen(ans);

                   }

               }

               memset(tmp,0,sizeof(tmp));

           }

       }

       if(L>=3) puts(ans);

       else puts("no significantcommonalities");

   }

}

 

 

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

 

#include<cstdio>

#include<cstring>

int n,m;

char a[1000],b[1000];

int p[1000];

void getp(){

   p[1]=0;

   int i,j=0;

   for(i=2;i<=m;i++){

       while(j>0&&b[j+1]!=b[i]) j=p[j];

       if(b[j+1]==b[i]) j+=1;

       p[i]=j;

   }

}

int kmp()

{

   int i,j=0,cnt=0;

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

       while(j>0&&b[j+1]!=a[i]) j=p[j];

       if(b[j+1]==a[i]) j+=1;

       if(j==m){

           cnt++;

           j=p[j];

       }

   }

   return cnt;

}

int main()

{

   while(scanf("%s%s",a+1,b+1)!=EOF)

   {

       m=strlen(b+1);

       n=strlen(a+1);

       getp();

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

   }

}

 

 

 

/*

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

 
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,
回文就是正反读都是一样的字符串,aba, abba
 
aaaa
abab
4
3
*/ 
 
#include<cstdio>
#include<cstring>
const int M = 110010*2;
char str[M];//start from index 1
int p[M];
char s[M];
int n;
void checkmax(int &ans,int b){
    if(b>ans) ans=b;
}
inline int min(int a,int b){
    return a<b?a:b;
}
void kp(){
    int i;
    int mx = 0;
    int id;
    for(i=1; i<n; i++){
        if( mx > i )
            p[i] = min( p[2*id-i], p[id]+id-i );
        else
            p[i] = 1;
        for(; str[i+p[i]] == str[i-p[i]]; p[i]++) ;
        if( p[i] + i > mx ) {
            mx = p[i] + i;
            id = i;
        }
    }
}
void pre()
{
    int i,j,k;
    n = strlen(s);
    str[0] = '$';
    str[1] = '#';
    for(i=0;i<n;i++)
    {
        str[i*2 + 2] = s[i];
        str[i*2 + 3] = '#';
    }
    n = n*2 + 2;
    str[n] = 0;
}
 
void pt()
{
    int i;
    int ans = 0;
    for(i=0;i<n;i++)
        checkmax(ans, p[i]);
    printf("%d\n", ans-1);
}
 
int main()
{
    int T,_=0;
    while( scanf("%s", s) !=EOF )
    {
        pre();
        kp();
        pt();
    }
    return 0;
}
 
 

7、容斥定理

 
/*
 
he wants to fire the people whose work number is co-prime with n next year.
 
2
4
5
 
82
354
Hint
Case1: sum=1+3*3*3*3=82
Case2: sum=1+2*2*2*2+3*3*3*3+4*4*4*4=354
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const __int64 mod = 1000000007;
__int64 n;
__int64 power(__int64 a,__int64 b,__int64 c)
{
    __int64 ret=1;
    while(b>0)
    {
        if(b&1)
            ret=ret*a%c;
        a=a*a%c;
        b>>=1;
    }
    return ret;
}
__int64  calc(__int64 n)
{
       __int64 a=n,b=(2*n+1),c=(n+1),d=(3*n*n+3*n-1)%mod;
       __int64 sum=1;
       sum*=a;sum%=mod;
       sum*=b;sum%=mod;
       sum*=c;sum%=mod;
       sum*=d;sum%=mod;
       __int64 t=power(30,mod-2,mod);
       return sum*t%mod;
}
__int64 sici(__int64 n)
{
    __int64 sum=1;
    for(int i=1;i<=4;i++)
    {
        sum*=n;
        if(sum>=mod) sum%=mod;
    }
    return sum;
}
__int64 solve(__int64 r,__int64 n)
{
    vector<__int64> p;
    __int64 i;
    for(i=2;i*i<=r;i++)
    {
        if(r%i==0)
        {
            p.push_back(i);
            while(r%i==0) r/=i;
        }
    }
    if(r>1) p.push_back(r);
    __int64 sum=0;
    for(__int64 num=1;num<(1<<p.size());num++)
    {
        __int64 mult=1,ones=0;
        for(i=0;i<p.size();i++)
        {
            if(num&(1<<i))
            {
                ones++;
                mult*=p[i];
                if(mult>=mod) mult%=mod;
            }
        }
        if(ones%2) sum+=sici(mult)*calc(n/mult);
        else sum-=sici(mult)*calc(n/mult);
        sum%=mod;
    }
    return sum;
}
int main()
 {
     __int64 t,i,j;
     scanf("%I64d",&t);
     while(t--)
     {
         scanf("%I64d",&n);
         printf("%I64d\n",(calc(n)-solve(n,n)%mod+mod)%mod);
     }
     return 0;
 }
 
 
/*

8、字典树的简单应用

 
banana
band
bee
absolute
acm
 
ba
b
band
abc
 
2
3
1
0
 
*/
#include<stdio.h>
#include<string.h>
char s[15];
class trie{
public :
    int num;
    trie* child[27];
    trie()
    {
        num=0;
        memset(child,0,sizeof(child));
    }
}root;
void insert(char *s)
{
    class trie *cur=&root;
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
      int id=s[i]-'a';
      if(!cur->child[id])
          cur->child[id]=new trie;
      cur=cur->child[id];
      cur->num++;
    }
}
int find(char *s)
{
     class trie *cur=&root;
     int len=strlen(s);
     for(int i=0;i<len;i++)
     {
         int id=s[i]-'a';
         if(!cur->child[id]) return 0;
         cur=cur->child[id];
     }
     return cur->num;
}
int main()
{
    while(gets(s))
    {
        if(strcmp(s,"")==0) break;
            insert(s);
    }
    while(scanf("%s",s)!=EOF)
        printf("%d\n",find(s));
    return 0;
}

 

 

 

8、括号匹配

 

 

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#define N 10005

char a[10005];

typedef struct{

      char*top;

      char*base;

      intstacksize;

}SqStack;

void InitStack(SqStack *s)

{

      s->base=(char*)malloc(N*sizeof(char));

      s->top=s->base;

      s->stacksize=N;

}

void Push(SqStack *s,char e)

{

      *s->top=e;

      s->top++;

}

char Pop(SqStack *s)

{

      --s->top;

      return*s->top;

}

char GetTOP(SqStack *s)

{

      return*(s->top-1);

}

 

int matching(char a[])

{

      inti,len;

      len=strlen(a);

      SqStacks;

      InitStack(&s);

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

      {

             if(a[i]=='('||a[i]=='[')

             Push(&s,a[i]);

             elseif(a[i]==')')

             {

                    if(s.top==s.base)

                    return0;

                    elseif(GetTOP(&s)=='(')

                         Pop(&s);

                         else

                         return 0;

             }

             elseif(a[i]==']')

             {

                    if(s.top==s.base)

                    return0;

                    elseif(GetTOP(&s)=='[')

                         Pop(&s);

                         else

                         return 0;

             }

      }

      if(s.top==s.base)

      return1;

      else

      return0;

}

int main()

{

      intzushu;

      scanf("%d",&zushu);

      while(zushu--)

      {

             scanf("%s",a);

             if(matching(a))

       printf("Yes\n");

       else

       printf("No\n");

      }

      return0;

}       

 

 

 

 

/*

 

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

如:dabdbf最长递增子序列就是abdf,长度为4

 

*/

#include<stdio.h>

int length(char * s)

{

              intlen[128] = {0}, i, t;

              for(;*s != '\0' && (t = len[*s - 1] + 1); s++)

              for(i= *s; i < 128 && len[i] < t; len[i++] = t);

              returnlen[127];

}

int main()

{

              intn;

              chars[10001];

              for(scanf("%d\n",&n); n--;)

              printf("%d\n",length(gets(s)));

              return0;

}

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

 

 

 

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
【5层】公司办公楼全套设计+++(3156平,含计算书、建筑图,结构图、实习报告,PKPM,答辩PPT) 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值