acm最终总结

ACM总结
本学期我选择了acm程序设计课,在跟随老师进行长达一个学期的算法学习中,我对程序算法有了更加深刻的了解,本学期主要学习了贪心、搜索、动态规划、图算法。接下来,我将针对这一个学期的算法课程进行总结。


1. 贪心算法


⑴ 有一个以最优方式来解决的问题。为了构造问题的解决方案,有一个候选的对象的集合:比如不同面值的硬币。
 
⑵ 随着算法的进行,将积累起其它两个集合:一个包含已经被考虑过并被选出的候选对象,另一个包含已经被考虑过但被丢弃的候选对象。
 
⑶ 有一个函数来检查一个候选对象的集合是否提供了问题的解答。该函数不考虑此时的解决方法是否最优。
 
⑷ 还有一个函数检查是否一个候选对象的集合是可行的,也即是否可能往该集合上添加更多的候选对象以获得一个解。和上一个函数一样,此时不考虑解决方法的最优性。
 
⑸ 选择函数可以指出哪一个剩余的候选对象最有希望构成问题的解。
 
⑹ 最后,目标函数给出解的值。
 
为了解决问题,需要寻找一个构成解的候选对象集合,它可以优化目标函数,贪婪算法一步一步的进行。起初,算法选出的候选对象的集合为空。接下来的每一步中,根据选择函数,算法从剩余候选对象中选出最有希望构成解的对象。如果集合中加上该对象后不可行,那么该对象就被丢弃并不再考虑;否则就加到集合里。每一次都扩充集合,并检查该集合是否构成解。如果贪婪算法正确工作,那么找到的第一个解通常是最优的。


经典例题:田忌赛马
如何赢得最多的比赛,关键在于最快的马和最慢的马,将情况分类讨论
 
    *1田快》齐快,田赢
 
    *2田快=齐快,田慢比齐快,田输
 
    *3田快《齐快,田和齐慢比,田输
 
    *4田慢》奇慢 ,田赢
 
    *5田慢《奇慢,田慢和齐快比,田输
 




#include<iostream>
 
#include<algorithm>
 
#include<map>
 
using namespacestd;
 
bool cmp(inta,int b)
 
{ returna>b;}
 
int main()
 
{   int n,i,w,l;
 
    int ta,ti,ka,ki;
 
    int a[1000];
 
    int b[1000];
 
    while(cin>>n)
 
    {  if(n==0) break;
 
           w=0;
 
           l=0;
 
        ta=ka=0;
 
           ti=ki=n-1;
 
         for(i=0;i<n;i++)
 
           cin>>a[i];
 
        for(i=0;i<n;i++)
 
           cin>>b[i];
 
        sort(a,a+n,cmp);
 
        sort(b,b+n,cmp);
 
        while(ta<=ti)
 
        {  if(a[ti]>b[ki])
 
           {       w++;
 
                ti--;
 
                ki--;
 
            }
 
            else if(a[ti]<b[ki])
 
                 {     l++;
 
                  ti--;
 
                  ka++;
 
            }
 
                 else
 
                       {  if(a[ta]>b[ka])
 
                             {
 
                       w++;
 
                       ta++;
 
                       ka++;
 
                             }
 
                     else
 
                             {
 
                         if(a[ti]<b[ka])
 
                           l++;
 
                           ti--;
 
                           ka++;
 
                             }
 
                       }
 
           }
 
        cout<<(w-l)*200<<endl;
 
      }
 
      return 0;
 
}
 




2. 搜索算法


dfs(深搜)
 
深搜,简言之就是不撞南墙不回头
 
顾名思义,深度优先搜索所遵循的策略就是尽可能“深”的在图中进行搜索,对于图中某一个顶点V,如果它还有相邻的顶点(在有向图中就是还有以V为起点的边)且未被访问,则访问此顶点。如果找不到,则返回到上一个顶点。这一过程一直进行直到所有的顶点都被访问为止。 DFS可以搜索出从某一个顶点到另外的一个顶点的所有路径。 由于要进行返回的操作,我们采用的是递归的方法。
 


bfs(广搜)
 
广搜,找眼镜式搜索,大面积寻找,找到为止
 
BFS的思想:
从一个图的某一个顶点V0出发,首先访问和V0相邻的且未被访问过的顶点V1、V2、……Vn,然后依次访问与V1、V2……Vn相邻且未被访问的顶点。如此继续,找到所要找的顶点或者遍历完整个图。
由此可以看出,用BFS进行搜索所搜索的顶点都是按深度进行扩展的,先找到到V0距离为1的所有顶点,然后找到距离V0为2的顶点……所以BFS所搜索到的都是最短的路径。
由于要将距离V0为d(d>0)的且未被方位的点都记录起来,我们采用队列这种数据结构。队列的特点是先进先出(FIFO),从某个顶点出发,记此顶点已访问标记,然后依次搜索和此顶点相邻的且未被访问的顶点,将其加入队列,并置已访问标记,重复此步骤,直到找到需要搜索的顶点或者所有的顶点都被访问为止。


BFS与DFS的讨论:BFS:这是一种基于队列这种数据结构的搜索方式,它的特点是由每一个状态可以扩展出许多状态,然后再以此扩展,直到找到目标状态或者队列中头尾指针相遇,即队列中所有状态都已处理完毕。
DFS:基于递归的搜索方式,它的特点是由一个状态拓展一个状态,然后不停拓展,直到找到目标或者无法继续拓展结束一个状态的递归。
          
优缺点:BFS:对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大(需要开大量的数组单元用来存储状态)。
         DFS:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,然而在深度很大的情况下效率不高
  
总结:不管是BFS还是DFS,它们虽然好用,但由于时间和空间的局限性,以至于它们只能解决数据量小的问题。
  
各种搜索题目归类:
  
坐标类型搜索 :这种类型的搜索题目通常来说简单的比较简单,复杂的通常在边界的处理和情况的讨论方面会比较复杂,分析这类问题,我们首先要抓住题目的意思,看具体是怎么建立坐标系(特别重要),然后仔细分析到搜索的每一个阶段是如何通过条件转移到下一个阶段的。确定每一次递归(对于DFS)的回溯和深入条件,对于BFS,要注意每一次入队的条件同时注意判重。要牢牢把握目标状态是一个什么状态,在什么时候结束搜索。还有,DFS过程的参数如何设定,是带参数还是不带参数,带的话各个参数一定要保证能完全的表示一个状态,不会出现一个状态对应多个参数,而这一点对于BFS来说就稍简单些,只需要多设置些变量就可以了。
  
  
数值类型搜索:(虽然我也不知道该怎么叫,就起这个名字吧),这种类型的搜索就需要仔细分析分析了,一般来说采用DFS,而且它的终止条件一般都是很明显的,难就难在对于过程的把握,过程的把握类似于坐标类型的搜索(判重、深入、枚举),注意这种类型的搜索通常还要用到剪枝优化,对于那些明显不符合要求的特殊状态我们一定要在之前就去掉它,否则它会像滚雪球一样越滚越大,浪费我们的时间。
经典例题:
Dfs
Problem Description
 自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视。
 据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖品———HDU免费七日游外加lcy亲笔签名以及同hdu acm team合影留念的机会。
 所以全球人民前仆后继,为了奖品日夜训练茶饭不思。当然也包括初学者linle,不过他太笨了又没有多少耐性,只能做做最最基本的数独题,不过他还是想得到那些奖品,你能帮帮他吗?你只要把答案告诉他就可以,不用教他是怎么做的。
 


数 独游戏的规则是这样的:在一个9x9的方格中,你需要把数字1-9填写到空格当中,并且使方格的每一行和每一列中都包含1-9这九个数字。同时还要保证, 空格中用粗线划分成9个3x3的方格也同时包含1-9这九个数字。比如有这样一个题,大家可以仔细观察一下,在这里面每行、每列,以及每个3x3的方格都 包含1-9这九个数字。
 
Input
 本题包含多组测试,每组之间由一个空行隔开。每组测试会给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开。其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数。
  
 Output
  对于每组测试,请输出它的解,同一行相邻的两个数用一个空格分开。两组解之间要一个空行。
 对于每组测试数据保证它有且只有一个解。
  
 Sample Input
 7 1 2 ? 6 ? 3 5 8
 ? 6 5 2 ? 7 1 ? 4
 ? ? 8 5 1 3 6 7 2
 9 2 4 ? 5 6 ? 3 7
 5 ? 6 ? ? ? 2 4 1
 1 ? 3 7 2 ? 9 ? 5
 ? ? 1 9 7 5 4 8 6
 6 ? 7 8 3 ? 5 1 9
 8 5 9 ? 4 ? ? 2 3
  
 Sample Output
 7 1 2 4 6 9 3 5 8
 3 6 5 2 8 7 1 9 4
 4 9 8 5 1 3 6 7 2
 9 2 4 1 5 6 8 3 7
 5 7 6 3 9 8 2 4 1
 1 8 3 7 2 4 9 6 5
 2 3 1 9 7 5 4 8 6
 6 4 7 8 3 2 5 1 9
 8 5 9 6 4 1 7 2 3
   


记下没有被赋值的位置,用dfs,每次赋值之前看看与原有数据是否冲突,不冲突的话,进行下一个深搜,最后得到结果
 
#include<iostream>
 #include<cstdio>
 #include<stdio.h>
 #include<cstring>
 #include<cmath>
 using namespace std;
 int row[12][12],cor[12][12],quq[3][3][12];
 int vis [25];
 char ma[50][50];
 int mapp[12][12];
 char ssss;
 struct point
 {
     int x;
     int y;
 };
 point pp[82];
 void dfs(int num)
 {
     int i,j;
     if(num==-1)
     {
         for(i=0;i<9;i++)
         {
             for(j=0;j<9;j++)
             {
                 if(j==0)
                     cout<<mapp[i][j];
                 else
                     cout<<" "<<mapp[i][j];
             }
             cout<<endl;
         }
         return ;
     }
     else
     {
 


        int x=pp[num].x;
         int y=pp[num].y;
 






        for(i=1;i<10;i++)
         {
             if(!row[x][i]&&!cor[y][i]&&!quq[x/3][y/3][i])
             {
                 mapp[x][y]=i;
                 row[x][i]=1;
                 cor[y][i]=1;
                 quq[x/3][y/3][i]=1;
                 dfs(num-1);
                 mapp[x][y]=0;
                 row[x][i]=0;
                 cor[y][i]=0;
                 quq[x/3][y/3][i]=0;
             }
         }
     }
 }
 int main()
 {
     int i,j;
     int coun=0;
     while(cin>>ssss)
     {
         int num=0;
         ma[0][0]=ssss;
         gets(ma[0]+1);
         for(i=0;ma[0][i]!='\0';i++)
         {
             if(ma[0][i]>='1'&&ma[0][i]<='9')
             {
                 mapp[0][num]=ma[0][i]-'0';
                 num++;
             }
             if(ma[0][i]=='?')
             {
                 mapp[0][num]=0;
                 num++;
             }
         }
         for(i=1;i<9;i++)
         {
             gets(ma[i]);
             num=0;
             for(j=0;ma[i][j]!='\0';j++)
             {
                 if(ma[i][j]>='1'&&ma[i][j]<='9')
                     mapp[i][num++]=ma[i][j]-'0';
                 if(ma[i][j]=='?')
                     mapp[i][num++]=0;
             }
         }
         num=0;
         memset(row,0,sizeof(row));
         memset(cor,0,sizeof(cor));
         memset(quq,0,sizeof(quq));
         for(i=0;i<9;i++)
         {
             for(j=0;j<9;j++)
             {
                 if(mapp[i][j])
                 {
                     row[i][mapp[i][j]]=1;
                     cor[j][mapp[i][j]]=1;
                     quq[i/3][j/3][mapp[i][j]]=1;
                 }
                 else
                 {
                     pp[num].x=i;
                     pp[num++].y=j;
                 }
             }
         }
         num--;
         if(coun!=0)
             cout<<endl;
         dfs(num);
         coun++;
 


    }
     return 0;
 }
Bfs
Problem Description
 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。 
 
Input
 三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
 
Output
 如果能平分的话请输出最少要倒的次数,否则输出"NO"。
 
Sample Input
 7 4 3
 4 1 3
 0 0 0
 
Sample Output
 NO
 


这是一道BFS,每次倒可乐动作可以看为:
 
从瓶中向第一个杯子倒,向第二个杯子倒;
 
从第一个杯子向瓶子倒,向第二个杯子倒;
 
从第二个杯子向瓶子倒,向第一个杯子倒。
 
六种情况
 
我的方法是每次要倒得时候判断,该容器可不可以倒可乐(该容器满没满)
 
然后是细节处理:
 
例如如果从第一个杯子向第二个杯子倒。
 
①第二个杯子是否可以倒可乐(是否满了)
 
②第一个杯子是否是空的
 
③第一个杯子向第二个杯子倒完后,会不会溢出。
 
④第一个杯子如果剩余,剩余多少(由第一个杯子原来是否有可乐决定)
 
VIS此处可以建立三维数组,让各个容器内可乐容量作为三个下标。
 
#include<iostream>
 #include<string.h>
 #include<set>
 #include<stdio.h>
 #include<vector>
 #include<algorithm>
 #include<numeric>
 #include<math.h>
 #include<string.h>
 #include<sstream>
 #include<stdio.h>
 #include<string>
 #include<cstdlib>
 #include<algorithm>
 #include<iostream>
 #include<map>
 #include<queue>
 #include<iomanip>
 #include<cstdio>
 using namespace std;
 int maxx(int a,int b)
 {
     int minn;
     minn=min(a,b);
     for(int i=minn;i>0;i--)
     {
         if(a%i==0&&b%i==0)
         return i;
     }
 }
 int main()
 {
     //freopen("r.txt","r",stdin);
     int s,n,m;
     while(cin>>s>>n>>m&&s!=0||n!=0||m!=0)
     {
         int t;
         t=s/maxx(n,m);
         if(t%2!=0) cout<<"NO"<<endl;
         else cout<<t-1<<endl;
     }
     return 0;
 }




3. 动态规划
动态规划是求解决策过程最优化的数学方法,把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。
在动态规划中主要有背包问题,线性规划,区间规划动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的(多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有"动态"的含义,称这种解决多阶段决策最优化问题的方法为动态规划方法)。


其中,状态转移方程:
 
f[i][j]=a[i][j] + min{f[i+1][j],f[i+1][j+1]}  (a[i][j]表示当前状态,f[i][j]表示函数)
 
经典例题:
Problem Description
 A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a banana at the roof of a building, and at the mean time, provide the monkey with some blocks. If the monkey is clever enough, it shall be able to reach the banana by placing one block on the top another to build a tower and climb up to get its favorite food.
 


The researchers have n types of blocks, and an unlimited supply of blocks of each type. Each type-i block was a rectangular solid with linear dimensions (xi, yi, zi). A block could be reoriented so that any two of its three dimensions determined the dimensions of the base and the other dimension was the height. 
 


They want to make sure that the tallest tower possible by stacking blocks can reach the roof. The problem is that, in building a tower, one block could only be placed on top of another block as long as the two base dimensions of the upper block were both strictly smaller than the corresponding base dimensions of the lower block because there has to be some space for the monkey to step on. This meant, for example, that blocks oriented to have equal-sized bases couldn't be stacked. 
 


Your job is to write a program that determines the height of the tallest tower the monkey can build with a given set of blocks.
  
 Input
 The input file will contain one or more test cases. The first line of each test case contains an integer n,
 representing the number of different blocks in the following data set. The maximum value for n is 30.
 Each of the next n lines contains three integers representing the values xi, yi and zi.
 Input is terminated by a value of zero (0) for n.
  
 Output
 For each test case, print one line containing the case number (they are numbered sequentially starting from 1) and the height of the tallest possible tower in the format "Case case: maximum height = height".
  
 Sample Input
 1 10 20 30 2 6 8 10 5 5 5 7 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 5 31 41 59 26 53 58 97 93 23 84 62 64 33 83 27 0
  
 Sample Output
 Case 1: maximum height = 40 Case 2: maximum height = 21 Case 3: maximum height = 28 Case 4: maximum height = 342
  
 Source
 University of Ulm Local Contest 1996
  
 Recommend
 
JGShining
 
3.题目:给出长方体,向上堆,猴子要吃上面的食物,尽量堆高
 要求下面的块的要比上面的大(长和宽),注意注意种长方体所给量都是无限的TT
 
4.动态规划
 


5.#include <stdio.h>
 #include<iostream>
 #include<cstdio>
 #include<string.h>
 #include<algorithm>
 using namespace std;
 int dp[111];
 struct ck
 {
     int c;
     int k;
     friend bool operator < (const ck &a,const ck &b)
     {
         if(a.c>b.c) return true;
         if(a.c==b.c&&a.k>b.k) return true;
         return false;
     }
 };
 struct rx
 {
     ck num;
     int len;
     friend bool operator < (const rx &a,const rx &b)
     {
         return a.num<b.num;
     }
 


}arr[100005];
 void paopao(int &a,int &b,int &c)
 {
     int t;
     if(a<b)
     {
         t=a;
         a=b;
         b=t;
     }
     if(a<c)
     {
         t=a;
         a=c;
         c=t;
     }
     if(b<c)
     {
         t=b;
         b=c;
         c=t;
     }
     return ;
 }
 int main()
 {
     int i,n,a,b,c,j;
    // freopen("r.txt","r",stdin);
     int cass=0;
     while(~scanf("%d",&n))
     {
         if(n==0) break;
         cass++;
         int pp=0;
         for(i=0;i<n;i++)
         {
             scanf("%d%d%d",&a,&b,&c);
             paopao(a,b,c);
             arr[pp].num.c=b;arr[pp].num.k=c;arr[pp++].len=a;
             arr[pp].num.c=a;arr[pp].num.k=c;arr[pp++].len=b;
             arr[pp].num.c=a;arr[pp].num.k=b;arr[pp++].len=c;
         }
         sort(arr,arr+pp);
        // for(i=0;i<pp;i++)
            // cout<<arr[i].num.c<<" "<<arr[i].num.k<<endl;
 


        for(i=0;i<pp;i++) dp[i]=arr[i].len;
         for(i=pp-2;i>=0;i--)
             for(j=i+1;j<pp;j++)
             {
                if(arr[i].num.c>arr[j].num.c&&arr[i].num.k>arr[j].num.k)//最大递减dp
                    if(dp[i]<dp[j]+arr[i].len)
                        dp[i]=dp[j]+arr[i].len;
             }
             int sumh=dp[0];
             for(i=0;i<pp;i++)
                 if(sumh<dp[i]) sumh=dp[i];
             printf("Case %d: maximum height = %d\n",cass,sumh);
 






       /* int dp[10005]={0};
         int temp;
         dp[0]=arr[0].len;
         for(i=1;i<pp;i++)
         {
             temp=-32768;
             for(j=0;j<i;j++)
             {
                 if(arr[j].num.c>arr[i].num.c&&arr[j].num.k>arr[i].num.k)
                 {
                     temp=max(temp,dp[j]);
                 }
             }
             dp[i]=arr[i].len+temp;
             //cout<<dp[i]<<endl;
         }
         temp=-32768;
         for(i=0;i<pp;i++)
         {
             if(dp[i]>temp)
                 temp=dp[i];
         }
         cout<<"Case "<<cass<<": maximum height = ";
         cout<<temp<<endl;*/
     }
 


    return 0;
 }


4. 图算法
生成树:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或Prim(普里姆)算法求出。
最短路径:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或Prim(普里姆)算法求出。 


最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。 算法具体的形式包括:
确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。
确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。
确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。
全局最短路径问题 - 求图中所有的最短路径。


经典例题:
有 N 的村庄,从 1 到 N 编号,和你应该有些修路,这样每两个村庄可以连接到彼此。我们说两个村庄 A 和 B 连接,当且仅当有一条路之间 A 和 B,或存在一个村庄 C 等,还有一条路之间连接 A 和 C,和 C 和 B。我们知道一些村庄之间已经有一些道路和你的工作是的生成一些道路这样的所有村庄都是连接和建的所有道路长度最小。输入第一行是一个整数 N (3 < = N < = 100),这是村庄的数字。然后来 N 行,其中第 i 个包含 N 的整数,而且这些 N 整数 j th 距离 (该距离应内的整数 [1,1000年]) 之间村庄 i 和村庄 j。然后还有一个整数 Q (0 < = Q < = N * (N + 1) / 2)。然后来的 Q 行,每行包含两个整数和 b (1 < = < b < = N),这意味着村庄之间的公路和村庄 b 建成。输出你应该输出行包含一个整数,是打造的所有村庄都被连接的所有道路的长度,此值是最低。
 


#include <iostream>
 #include <queue>
 #include<stdio.h>
 using namespace std;
 const long MAXN=10000;
 long father[MAXN];
 long m,n;//点数 边数
 //m标号从1开始
 typedef struct
 {
     long from;
     long to;
     long cost;
 }Edge;
 


bool operator <(const Edge &a, const Edge &b)
 {
     return a.cost>b.cost;
 }
 priority_queue<Edge> q;
 Edge e[100005];
 void MakeSet()
 {
     long i;
     for (i=0;i<=m;++i)
     {
         father[i]=i;
     }
 }
 long Find(long i)
 {
     long r=i;
     while (father[r]!=r)
     {
         r=father[r];
     }
     while (father[i]!=r)
     {
         long j=father[i];
         father[i]=r;
         i=j;
     }
     return r;
 }
 void Unition(long x,long y)
 {
     long fx=Find(x);
     long fy=Find(y);
     if (fx!=fy)
     {
         father[fx]=fy;
     }
 }
 void Init()
 {
     while (!q.empty())
     {
         q.pop();
     }
     MakeSet();
     long i,j;
     long cc;
     int pp=0;
     for(i=1;i<=m;++i)
     {
         for(j=1;j<=m;j++)
         {
             scanf("%ld",&cc);
             e[pp].from=i;
             e[pp].to=j;
             e[pp].cost=cc;
             pp++;
         }
     }
     long qqq,aaa,bbb;
     scanf("%ld",&qqq);
     for(i=0;i<qqq;i++)
     {
         scanf("%ld%ld",&aaa,&bbb);
         for(j=0;j<pp;j++)
         {
             if(e[j].from==aaa)
             {
                 if(e[j].to==bbb)
                 {
                     e[j].cost=0;
                 }
             }
             if(e[j].from==bbb)
             {
                 if(e[j].to==aaa)
                 {
                     e[j].cost=0;
                 }
             }
         }
     }
     for(i=0;i<pp;i++)
     {
         q.push(e[i]);
     }
 }
 void print(long cost)
 {
     printf("%ld\n",cost);
 }
 void Kruskal()
 {
     Init();
     long t=0;//表示合并次数
     long cost=0;
     Edge e;
     while (!q.empty()&&t<m-1)
     {
         e=q.top();
         long v1=e.from;
         long v2=e.to;
         if (Find(v1)!=Find(v2))
         {
             Unition(v1,v2);
             cost+=e.cost;
             ++t;
         }
         q.pop();
     }
     print(cost);
 }
 


int main()
 {
     while(~scanf("%ld",&m))//输入点与边
     {
         Kruskal();
     }
     return 0;
 }
 


.



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值