最小生成树、次生成树、最短路劲、0-背包总结

1、最短路径

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

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

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

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

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

接下来M行,每行包括3个整数A,B,C(1<=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()

{

    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;

}

 

 

 

2、最小生成树:v + v + value布线问题完全路线

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

引水工程:它们可以自建水库解决缺水问题

 

/*

1

V e

4 6

 

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)

{

         intlowcost[MAX];

         intmst[MAX];

         inti, 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;

                            }

                   }

         }

         returnsum;

}

 

int main()

{

         inti, j, k, m, n;

         intx, y, cost;

         intzushu;

         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)

                   {

                            intt;

                       cin>>t;

                            if(t<min_v)

                            min_v=t;

                   }

                  

             cout <<cost+min_v<< endl;

         }

         return0;

}

 

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

 

3、最小生成树:v + v + value完全路线

/*

得到的统计表中列出了任意两村庄间的距离

3

1 2 1

1 3 2

2 3 4

4

1 2 1

1 3 4

1 4 1

2 3 3

2 4 2

3 4 5

0

*/

 

 

#include<iostream>

#include<cstdio>

using namespace std;

#define MAX 505

#define MAXCOST 0x7fffffff

 

int graph[MAX][MAX];

 

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

{

         intlowcost[MAX];

         intmst[MAX];

         inti, 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;

                            }

                   }

         }

         returnsum;

}

 

int main()

{

         inti, j, k, m, n;

         intx, y, cost;

   

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

         {

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

                    

                    n=(m*(m-1))/2;

                  

        

                   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);

             cout <<cost<< endl;

           

         }

             

         return0;

}              

 

4、prim算法之矩阵类型

/*

1

3(3*3的矩阵)

0 990 692

990 0 179

692 179 0

*/

#include "stdio.h"

#include "string.h"

#define N 500

#define INT 10000

bool vis[N];

int dis[N];

int a[N][N];

int main(){

         intt;

         scanf("%d",&t);

         while(t--){

                   intn;

                   scanf("%d",&n);

                   inti,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];

                                     }

                            }

                   }

                   intmax=0;

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

                            if(max<dis[i])

                                     max=dis[i];

                   }

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

         }

         return0;

}

 

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

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()

{

    inti,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()

{

    inti,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;

}

 

 

 

 

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

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()

{

    intlowcost[MAX ];

    intclosest[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数组中了。遍历一下就可以得到最大最小值。

    intresult=-1;

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

      {

          if(result<lowcost[i])

           result=lowcost[i];

      }

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

}

int main()

{

    intt;

   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;

}

 

 

 

 

7、prim算法变形之引水工程

 /*1

         5

  0 5 44 3 6

  5 0 22 2 2

  4  2 0 3 3 3

  4  2 3 0 4 5

  3  2 3 4 0 1

  5  2 3 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()

{

    inti,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()

{

    inti,v,j,ans,zushu;

   scanf("%d",&zushu);

    inta[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;

}

 

 

       

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

省政府“畅通工程”的目标是

 

使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。

现请你编写程序,计算出全省畅通需要的最低成本。

Input

测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N

行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。

为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。

Output

对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。

 

 

 

Sample Input

3 3

1 2 1

1 3 2

2 3 4

1 3

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 //存储边的信息

{

         inta;

         intb;

         intvalue;

};

 

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

{

         returna.value < b.value;

}

 

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

{

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

}

 

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

{

         introot1, root2;

         root1= unionsearch(x);

         root2= unionsearch(y);

         if(root1== root2) //为环

                   returnfalse;

         elseif(son[root1] >= son[root2])

                   {

                            father[root2]= root1;

                            son[root1]+= son[root2];

                   }

                   else

                   {

                            father[root1]= root2;

                            son[root2]+= son[root1];

                   }

         returntrue;

}

 

int main()

{

         intltotal, sum, flag;

         Kruskaledge[MAX];

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

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

         {

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

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

                   {

                            father[i]= i;

                            son[i] = 1;

                   }

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

                   {

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

                   }

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

                  

                   intcount=0;

                  

                   for(inti = 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");

                  

         }

         return0;

}

 

9、还差多少对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) //查找父节点+路径压缩(非递归)

{

    intson, 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) //查找父节点+路径压缩(递归)

{

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

}*/

 

int main()

{

    intnum, 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;

}

 

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

/*

对每个测试用例,在 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) //查找父节点+路径压缩(非递归)

{

    intson, 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)

{

         intlowcost[MAX];

         intmst[MAX];

         inti, 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;

                            }

                   }

         }

         returnsum;

}

 

int main()

{

    intnum, road, total, start, end, root1, root2;

   

    inti, j, k, m, n;

         intx, y, cost;

         intzushu;

         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("Nosolution\n");

       }

         }

   return 0;

}

 

11、dfs 欧拉回路

/*

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() {

    intkase,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、两列相同数的最大匹配数

/*

1

3(3男3女) 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) //匈牙利算法

{

         inttemp;

         for(inti = 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;

                            }

                   }

         }

         returnfalse;

}

 

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

{

         intsumall = 0;

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

         {

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

                   if(find(i))

                            sumall++;

         }

         returnsumall;

}

 

int main()

{

         intncase;

         intallnum, relation;

         intu, v;

         scanf("%d",&ncase);

         while(ncase--)

         {

                   num= 0;

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

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

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

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

                   {

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

                            add(u,v);

                   }

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

         }

         return0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                  

2.0-1背包

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

/*

 

13、0-1背包模板 苹果

 

描述

ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。

 

输入有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n、v同时为0时结束测试,

此时不输出。接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w。所有输入数字的范围大于等于0,

小于等于1000。输出对每组测试数据输出一个整数,代表能放入背包的苹果的总价值。样例输入

3 3

 1 1

 2 1

 3 1

 0 0

样例输出2

来源动态规划经典问题上传者ctest*/

 //经典的算法

#include<stdio.h>

 #include<string.h>

 intmax(int k,int m)

 {return m>k?m:k;}

 intc[1001],w[1001],dp[1010][1010];

 main()

 {

  intn,v;

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

  {

   memset(dp,0,sizof(dp));//此函数包含在string头文件里

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

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

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

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

    {

    if(j<c[i]) dp[i][j]=dp[i-1][j];

    else dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);

    }

   printf("%d\n",dp[n][v]);

  }

 }

 //改进的算法

#include<stdio.h>

 #include<string.h>

 intmax(int k,int m)

 {return k>m?k:m;}

 intdp[1010];

 main()

 {

  intn,v,i,j;

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

  {

  memset(dp,0,sizeof(dp));//此函数包含在string头文件里

  intc,w;

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

   {

   scanf("%d%d",&c,&w);

   for(j=v;j>=c;j--)

    {

    dp[j]=max((dp[j-c]+w),dp[j]);

    }

   }

  printf("%d\n",dp[v]);

  }

 }

 

-

 

 

/*

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

input:

5 2

1 2 3 4 5

1 3

2 4

output:

6

9

*/

#include<iostream>

#include<cstdio>

using namespace std;

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

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

//求最小幂2的k次幂

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

//求前n项和

int sum(int end)

{

         intsum=0;

         while(end>0)

         {

                   sum+=C[end];

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

         }

         returnsum;

 }

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

 voidPlus(int pos,int num)

 {

        while(pos<=n)

        {

                 C[pos]+=num;

                 pos+=lowbit(pos);

          }

}

int main()

{

         intzishu,i;

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

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

         {

                   inttemp;

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

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

         }

         while(zishu--)

         {

                   intmin,max;

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

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

          }

         return0;

}

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

/*

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

问题一:给你N个数和M次操作,操作分两种——

1,U a b 第a个数增加b;2,S a b  求区间[a, b]的和。

 

 

input:

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开始

//求最小幂2的k次幂

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

//求前n项和

int sum(int end)

{

         intsum=0;

         while(end>0)

         {

                   sum+=C[end];

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

         }

         returnsum;

 }

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

 voidPlus(int pos,int num)

 {

        while(pos<=n)

        {

                 C[pos]+=num;

                 pos+=lowbit(pos);

          }

}

int main()

{

         intzishu,i;

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

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

         {

                   inttemp;

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

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

         }

         while(zishu--)

         {

                   intmin,max;

                   charch[10];

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

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

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

                   else

                   Plus(min,max);

          }

         return0;

}

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

3、/*

那么我们用sum[n]代表前n项和,s[n]代表前n个sum和

ans = m*sum[i]-(s[i-1]-s[i-1-m])

*/

 

#include <stdio.h>

#include <algorithm>

using namespace std;

int sum[1000005],s[1000005];

int main()

{

    intn,m,a,i,j,k;

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

    {

       sum[0] = s[0] = 0;

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

       {

           scanf("%d",&a);

           sum[i] = sum[i-1]+a;

           s[i] = s[i-1]+sum[i];

       }

       if(n<=m)

       {

           printf("%d\n",sum[n]);//?

           continue;

       }

       int ans = 0,maxn = 0;

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

       {

           ans = m*sum[i]-(s[i-1]-s[i-1-m]);//?

           maxn = max(maxn,ans);

       }

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

    }

 

   return 0;

}

 

-------------------------------------树状数组------------------------------------------------------------------

 

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 110

//创建map二维数组储存图表,low数组记录每2个点间最小权值,visited数组标记某点是否已访问

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

int n;

 

int prim()

{

        

         /*

         4

         04 9 21

         40 8 17

         98 0 16

         2117 16 0

         */

    inti,j,pos,min,result=0;

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

//从某点开始,分别标记和记录该点

 

//从一开始,标记一下给位置,并且记录了他的位置。

   visited[1]=1;pos=1;

   

//第一次给low数组赋值

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

       if(i!=pos)

                   low[i]=map[pos][i];

                   //low[1]=0(这个元素直接跳过),low[2]=4,low[3]=9,low[4]=21

                  

//再运行n-1次

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

    {

        //找出最小权值并记录位置

        min=MaxInt;

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

        {    //第一次执行前已经,visited[1]=1

              //j=1, visited[1]=1

              //j=2,visited[2]=0,min=maxint,low[2]=4, min=4,pos=2;

              //j=3,visited[3]=0,low[3]=9,             bi

                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;

   n=4;

   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();

   return 0;

}

 

 

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

修路方案

时间限制:3000 ms |  内存限制:65535 KB

难度:5

描述

南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。

 

现在已经知道哪些城市之间可以修路,如果修路,花费是多少。

 

现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。

 

但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧。

 

输入

第一行输入一个整数T(1<T<20),表示测试数据的组数

每组测试数据的第一行是两个整数V,E,(3<V<500,10<E<200000)分别表示城市的个数和城市之间路的条数。数据保证所有的城市都有路相连。

随后的E行,每行有三个数字A B L,表示A号城市与B号城市之间修路花费为L。

输出

对于每组测试数据输出Yes或No(如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)

样例输入

2

3 3

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

{

 intx,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]) ;

 returnfather[x];

}

void Union(int x,int y)

{

 intt1,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)

{

 intsum=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];

  }

 }

 returnsum;

}

int AKrusual(int V,int E)

{

 Init(V);

 intsum=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);

  }

 }

 returnsum;

}

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

{

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

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

 returnfalse;

 returntrue;

}

int main()

{

 inttest,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);

  intsum=Krusual(V,E);

  intM=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");

  elseprintf("No\n");

 }

}

 

 

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

 

 

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int inf=0x3f3f3f3f;

const int maxn=505;

int map[maxn][maxn];

bool vis[maxn];

int low[maxn];

int mst[maxn][maxn],pre[maxn];

bool inmst[maxn][maxn];

int n,m;

void init()

{

         memset(map,inf,sizeof(map));

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

         {

                   map[i][i]=0;

         }

}

void slove()

{

         intmincost=0;

         intnext,Min;

         memset(inmst,0,sizeof(inmst));

         memset(mst,0,sizeof(mst));

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

         {

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

                   vis[i]=0;

                   pre[i]=1;

         }

         vis[1]=1;

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

         {

                   Min=inf;next=-1;

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

                   {

                            if(!vis[j]&&Min>low[j])

                            {

                                     next=j;

                                     Min=low[j];

                            }

                   }

                   mincost+=Min;

                   vis[next]=1;

                   intfa=pre[next];

                   inmst[next][fa]=inmst[fa][next]=1;

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

                   {

                            if(vis[j]&&j!=next)

                            {

                                     mst[j][next]=mst[next][j]=max(mst[fa][j],low[next]);

                            }

                            if(!vis[j]&&low[j]>map[next][j])

                            {

                                     low[j]=map[next][j];

                                     pre[j]=next;

                            }

                   }

         }

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

         {

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

                   {

                            if(map[i][j]!=inf&&!inmst[i][j])

                            {

                                     if(map[i][j]==mst[i][j])

                                     {

                                               printf("Yes\n");

                                               return;

                                     }

                            }

                   }

         }

         printf("No\n");

}

int main()

{

         intt;

         scanf("%d",&t);

         while(t--)

         {

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

                   init();

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

                   {

                            inta,b,c;

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

                            map[a][b]=map[b][a]=min(map[a][b],c);

                   }

                   slove();

         }

         return0;

}       

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include<iostream>

using namespace std;

int n, mid;

 

int Partition(int arr[], int low, int high)

{

         inti, 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--]);

         }

         returnj; //返回基准元素位置

}

 

void Quick_Sort(int arr[], int low, int high)

{

         intpivotpos;

         if(low<= high)

         {

                   pivotpos= Partition(arr, low, high);

                   if(pivotpos> n / 2)

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

                   elseif(pivotpos < n / 2)

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

                   else

                            mid= arr[pivotpos];

         }

}

 

int main()

{

         intcount = 0;

         printf("输入数组元素的个数:");

         scanf("%d",&n);

         int*a = new int[n];

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

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

         Quick_Sort(a,0, n - 1);

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

                   if(a[i]== mid)

                            count++;

         printf(count> n / 2 ? "Yes\n" : "No\n");

         deletea;

         return0;

}

17、数组快排

 

#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;

         inti, 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); //递归右边

}

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

 

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

int Partition(int low, int high)

{

         inti, 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--]);

         }

         returnj; //返回基准元素位置

}

 

void Quick_Sort(int low, int high)

{

         intpivotpos;

         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)

{

         intpivotpos, num;

         if(low== high)

                   returnarr[high];

         pivotpos= Partition(low, high);

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

         if(k== num)

                   returnarr[pivotpos];

         elseif(k < num)

                   returnselect(low, pivotpos - 1, k);

         else

                   returnselect(pivotpos + 1, high, k - num);

}

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

 

int main()

{

         intk;

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

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

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

         QuickSort(0,9);

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

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

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

         cout<<endl;

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

         cin>>k;

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

         return0;

}

 

 

18、并差集核心算法

 

int pre[1010]; //存放第i个元素的父节点

 

int unionsearch(int root) //查找根结点

{

         intson, tmp;

         son= root;

         while(root!= pre[root]) //寻找根结点

                   root= pre[root];

         while(son!= root) //路径压缩

         {

                   tmp= pre[son];

                   pre[son]= root;

                   son= tmp;

         }

         returnroot;

}

 

void join(int root1, int root2) //判断是否连通,不连通就合并

{

         intx, y;

         x= unionsearch(root1);

         y= unionsearch(root2);

         if(x!= y) //如果不连通,就把它们所在的连通分支合并

                   pre[x]= y;

}

 

19、数状数组核心

 

int lowbit(int n) //计算res数组中第n个位置掌管的元素个数

{

         returnn & (-n);

         //returnn&(n^(n-1)); //结果同上

}

 

void add(int i, int plus) //将第i个元素增加plus(更新)

{

         while(i<= N)

         {

                   res[i]+= plus;

                   i+= lowbit(i); //只更新与之关联的res数组元素

         }

}

 

int sum(int n) //求前n项的和

{

         intresult = 0;

         while(n> 0)

         {

                   result+= res[n];

                   n-= lowbit(n); //只加上范围最大的res数组元素

         }

         returnresult;

}

20、二分

 

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

{

         intlow = 0, high = n;

         while(low< high)

         {

                   intmid = low + (high - low) / 2;

                   if(arr[mid]== key)

                   {

                            cout<<"fad";

                            returnmid;

                   }

 

 

                   elseif(arr[mid] > key)

                            high= mid;

                   else

                            low= mid + 1;

         }

         return-1;

}

 

 

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

输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);
第二行有徐总的所在地start,他的目的地end;
接着有n行,每行有站名s,站名e,以及从s到e的时间整数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 supermarket 10

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)

{

         intk, temp;

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

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

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

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

         {

                   temp= MAX;

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

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

                                     temp= dis[k = j];

                   visit[k]= 1;

                   if(temp== MAX) break;

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

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

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

         }

}

 

int main()

{

         intnum, iterator, distance, flag;

         charbegin[30], end[30];

         chara[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(inti = 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");

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

         }

         return0;

}

 


22、最短路径  求最短距离

 


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

 

Input

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


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

 

 

Output

对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-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)

{

    int temp, k;

    CLR(visit,false);

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

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

    visit[start] =true;

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

    {

       temp = MAX;

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

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

              temp =dis[k = j];

       if(temp ==MAX)

           break;

       visit[k] =true;

       for(int j =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(int j= 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;

}

 

 

 

 

 

 

 

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

 

 6(6条路) 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;

#define MAX0x3f3f3f3f

int road,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];

    }

}

 

int main()

{

    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;

}

 

 

23、简单最大流

 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()

{

         inttemp;

         queue<int>q;

         visit[1]= true;

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

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

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

                   flow[i]= MAX;

         q.push(1);

         while(!q.empty())

         {

                   temp= q.front();

                   q.pop();

                   if(temp== n)

                            break;

                   for(inti = 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

                   returnflow[n];

}

 

int EK()

{

         inttemp, 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;

                   }

         }

         returnmaxflow;

}

 

int main()

{

         intncase, T = 1;

         intstart, end, capacity;

         scanf("%d",&ncase);

         while(ncase--)

         {

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

       // v e

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

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

                   {

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

                            cost[start][end]+= capacity;

                   }

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

         }

         return0;

}

 

 

 

25、线段树

本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。

 

 

#include<cstdio>

#include<algorithm>

#include<cmath>

using namespace std;

 

#define lson l, m, root << 1

#define rson m + 1, r, root << 1 | 1

const int N = 200010;

int segtree[N << 1 + 10]; //开2倍

 

void PushUp(int root) //节点保存区间最大值

{

       segtree[root]= max(segtree[root << 1], segtree[root << 1 | 1]);

}

 

void Build_Tree(int l, int r, int root)

{

       if(l ==r)

       {

              scanf("%d",&segtree[root]);

              return;

       }

       int m =(l + r) >> 1;

       Build_Tree(lson);

       Build_Tree(rson);

       PushUp(root);

}

 

void Update(int pos, int data, int l, int r, introot)

{

       if(l ==r)

       {

              segtree[root]= data;

              return;

       }

       int m =(l + r) >> 1;

       if(pos<= m)

              Update(pos,data, lson);

       else

              Update(pos,data, rson);

       PushUp(root);

}

 

int Query(int L, int R, int l, int r, int root)

{

       int sum= -9999999;

       if(L<= l && r <= R)

              returnsegtree[root];

       int m =(l + r) >> 1;

       if(L<= m)

              sum= max(sum, Query(L, R, lson));

       if(R> m)

              sum= max(sum, Query(L, R, rson));

       returnsum;

}

 

int main()

{

       intnum, que;

       charope;

       int a,b;

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

       {

              Build_Tree(1,num, 1);

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

              {

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

                     if(ope== 'U')

                            Update(a,b, 1, num, 1);

                     else

                            printf("%d\n",Query(a, b, 1, num, 1));

              }

       }

       return0;

}

 

 

 

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

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)

{

       inti,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()

{

       intn,m;

       intu,e,l;

       inti,j,k;

       intsum=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);

       }

       return0;

}       

27、0-1背包苹果

3(苹果个数) 3(c)

Wv
1 1
2 1
3 1
0 0

 

求出能放入背包的苹果的总价钱最大值。

 

#include<stdio.h>
#include<string.h>
int max(int k,int m)
{return k>m?k:m;}
int dp[1010];
main()
{
 int n,v,i,j;
 while(scanf("%d%d",&n,&v),n&&v)
 {
  memset(dp,0,sizeof(dp));//此函数包含在string头文件里 
  int c,w;
  for(i=1;i<=n;i++) 
  {
   scanf("%d%d",&c,&w);
   for(j=v;j>=c;j--)
   {
    dp[j]=max((dp[j-c]+w),dp[j]);
   }
  }
  printf("%d\n",dp[v]);
 }

 

 

28、0-1求所有挑选方案中物品价值总和的最大值。

4 n个)5c

W v

2 3

1 2

3 4

2 2

 

#include<stdio.h> 

#include<algorithm> 

#include<string.h> 

using namespace std; 

int n,m; 

int value[111]; 

int weight[111]; 

int dp[111111]; 

int V; 

int main() 

    int i,j; 

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

    { 

        V=0; 

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

        { 

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

           V+=value[i]; 

        } 

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

       {dp[i]=999999999;} 

       dp[0]=0;              //<spanstyle="color:#339999;">//初始化价值为0的重量为0</span> 

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

        { 

           for(j=V;j>=value[i];--j) 

            { 

               dp[j]=min(dp[j],dp[j-value[i]]+weight[i]); 

            } 

        } 

       for(i=V;i>=0;--i) 

        { 

           if(dp[i]<=m) 

           {printf("%d\n",i);break;} 

        } 

    } 

    return 0; 

}

 

 

290-1背包

 

4n 5c

W v

2 3

1 2

3 4

2 2

 

#include <iostream>

#include <cstdio>

#include <cstring>

#define INF 0x3f3f3f3f

#define N 10010

usingnamespacestd;

intres[N],w[110],v[110];

intW,n;

 

intmain()

{

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

    {

        res[0]=0;

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

            res[i]=INF;

        intsum=0;

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

        {

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

            sum+=v[i];

        }

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

        {

            for(intj=sum;j>=v[i];j--)

            {

                res[j]=min(res[j],res[j-v[i]]+w[i]);

            }

        }

        for(inti=sum;i>=0;i--)

            if(res[i]<=W)

            {

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

                break;

            }

    }

   

    return0;

}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值