程序设计week6作业

A - 氪金带东

在这里插入图片描述
Input
输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。
Output
对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N).
Sample Input
5
1 1
2 1
3 1
1 1
Sample Output
3
2
3
4
4
解题过程
这是一个树结构,题目的要求是求某一点的最长路。虽然第一反应是写一个图,邻接链表什么的,stl真好
树的直径是树上距离最远的两点间的距离,任意一点的最长路应该是与两个端点的距离。
找一个任意点为根,dfs整棵树找到距离他最远的点,再以这个点为根求出距离它最远的点,这两个点就是端点。
找各个点到两个端点的距离,保存最大的距离。

#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
struct wedge
{ int v1;
  
  int w;	
};
vector<wedge> g [10020];
int dis[10020];
int edgenum;
int max2,maxd;
void addedge(int v1,int v2,int w)
{ wedge a;
  a.v1=v1;a.w=w;
  g[v2].push_back(a);
  a.v1=v2;
  g[v1].push_back(a);	
}

void dfs(int start,int e,int d,int maxn[])
{ if(maxd<=d){
		maxn[0]=start;
		maxd=d;  
	}
	for(int i=0;i<g[start].size() ;i++){
		
	    if(g[start][i].v1==e)
		continue;
		dfs(g[start][i].v1,start,d+g[start][i].w,maxn);
	    dis[g[start][i].v1]=max(dis[g[start][i].v1],d+g[start][i].w);
	}
	
}

int  main(int  argc, char** argv) {
    //cout<<10001*10001*sizeof(int)/1024  ; 
    int n;
    while(scanf("%d",&n)!=EOF)
    {   
		 maxd=0;
	  for(int i=0;i<=n+1;i++)
       { g[i].clear();
       	 dis[i]=0;
	   }
	
	    for(int i=2;i<=n;i++)
      { int v,t;
        cin>>v>>t;
        addedge(i,v,t);
      	
	  }
     	 int maxn[1]={0};
       dfs(1,-1,0,maxn);
	   dfs(maxn[0],-1,0,maxn);
	   dfs(maxn[0],-1,0,maxn);	
    	for(int i=1;i<=n;i++)
    	cout<<dis[i]<<endl;
    	
	}
    
    
    
	return 0;
}

B - 戴好口罩!

在这里插入图片描述

解题过程
并查集很神奇,去年学kruskal的时候有了解过,就是只储存元素的父节点,通过寻找最终的父节点判断两个元素是否是属于同一个集合,刚知道的时候觉得这个好强,又简单又好使
用去年写的并查集结果一直runtime error(偷懒的报应 ) ,怪不得kruskal不好使原来是并查集写错了,持续半年的未解之谜得到了破解 太菜了只能重新写,结果又wa……果然躲过的最后还是得补回来。
用一个dis数组保存集合元素数,在合并集合时将小集合并到大集合里,更新两个元素所在集合的元素数。最后0所在的集合的元素数就是所求答案。

#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
 
struct unionFindNode
{
   int parent;  
   bool root;   

   unionFindNode()
      {parent = -1; root = true;}
};
int dis[400001];
class fastUnionFind
{
   public:
      fastUnionFind(int n)
      {// 初始化
        node = new unionFindNode[n+1];
        for(int i=0;i<n;i++)
        { node[i].parent=i;
          dis[i]=1;
		}
      }
      
      void unite(int rootA, int rootB)
      {int a=find(rootA),b=find(rootB);
       if(a==b)
       return;
       if(dis[a] >dis[b] )
	   {	swap(a,b);} 
		node[a].parent=b; 
		dis[a]=dis[a]+dis[b];  
	    dis[b]=dis[a]; 
       
      }
      
      int find(int e)
      {if(node[e].parent==e)
       return e;
       else 
       return find(node[e].parent);
         
      }
      
     private:
      unionFindNode *node;
};
int  main(int  argc, char** argv) {
    int n,m;
    while(1)
    {   cin>>n;
	    cin>>m;
      fastUnionFind a(n+1);
      if(n==0&&m==0)
      break;
      int num=0;
      for(int i=0;i<m;i++)
      { cin>>num;
        int a1,a2;
        cin>>a1;
       
	    for(int u=1;u<num;u++)
        {   cin>>a2;
             a.unite(a1,a2);
        	
		}
       	
	   	
	  }
	
    	cout<<dis[a.find(0)]<<endl;
	}
       
    
	return 0;
}

C - 掌握魔法の东东 I

在这里插入图片描述
解题过程
当很菜很菜的我知道这个题是要用图来做,感觉很奇妙。地与地之间的连接是边,消耗的mp用权来表示,黄河是一个和所有地连接的点,然后就是一个求最小生成树的问题。就kruskal。
借用了上一题的并查集虽然集合元素数没什么用了但是用是否是根判断改哪个父节点出现了不明错误……后来发现就是有时集合和点合并的时候集合内元素的父节点变成点了就可能和一部分集合内元素断了应该是判断没写好…。
kruskal是取最短的边直到会成环(并查集判断)或者边取没了,将取出的那些边权重相加就可以得到最少消耗mp的方案。

#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
struct wedge
{ int v1;
  int v2;
  int w;	
};
wedge g [200020];
wedge edges [200020];
void addedge(int v11,int v22,int ww,int i)
{  g[i].v1 =v11;
   g[i].w=ww;
   g[i].v2=v22;	
}
struct unionFindNode
{
   int parent;  
   bool root;   

   unionFindNode()
      {parent = 0; root = true;}
};
int dis[400];
bool cmp(wedge a, wedge b){
	return a.w < b.w;
}
class fastUnionFind
{
   public:
      fastUnionFind(int n)
      {// 初始化
        node = new unionFindNode[n+1];
        for(int i=0;i<n;i++)
        { node[i].parent=i;
          dis[i]=1;
		}
      }
      
      void unite(int rootA, int rootB)
      {int a=find(rootA),b=find(rootB);
       if(a==b)
       return;
       if(dis[a] >dis[b] )
	   {	swap(a,b);} 
		node[a].parent=b; 
		dis[a]=dis[a]+dis[b];  
	    dis[b]=dis[a]; 
       
      }
      
      int find(int e)
      {if(node[e].parent==e)
       return e;
       else 
       return find(node[e].parent);
         
      }
      
     private:
      unionFindNode *node;
};
      void kruskal( int n,int ee)
      {  
         
         fastUnionFind uf(n+5); 
         int sum=0;
         int k = 0; int i=0; 
         while (ee >=0 &&k<=n )
         { wedge x = g[i];  
            i++;
            ee--;
            int a = uf.find(x.v1);
            int b = uf.find(x.v2);
            if (a != b)
            {  edges[k++]=x;
               uf.unite(a,b);
              sum=sum+x.w;
            }
            
            
         }
            
	  	    cout<<sum<<endl;
      }
      

int  main(int  argc, char** argv) {
    
    int n,e=0;
    cin>>n;
    for(int i=1;i<=n;i++)
    {int w;
    cin>>w;
    addedge(0,i,w,e);
    e++;
	
	}
    for(int i = 1; i <= n; i++)
	{
	 for(int j = 1; j <= n; j++)
	 {int w;
	  cin >> w;
	  if(j > i)
	  {
	  addedge(i,j,w,e);
	  e++;
	  
	  }
	  
		}
	}
	sort(g,g+e,cmp);
	
    kruskal(n,e);
    
	return 0;
}

D - 数据中心

在这里插入图片描述
解题过程
这个题有点难读(梦回高中),看了样例说明感觉应该是求最小生成树的最长边,原来不需要加其他节点之间的传输时间吗。借用了上一题的全部代码(太懒了)然后把kruskal里的求权重和改成输出最后取出的边的权(它一定是最小生成树最长的一个边)。
提交的时候在test25卡了一分钟,心想果然是不行,结果又跳到106卡了一分钟,心想果然是不行,然后107卡了一分钟 居然过了。总觉得好像少干了点什么。如果没有那个样例提示我感觉我应该还在痴迷于算传输时间,好像原题也明说了虽然是看了提示才发现的,差点自以为是地误入歧途了,高中的时候就不好好读题,果然读题也是一种考试能力吗。
并查集的find忘记路径压缩了,不过合并的时候是是用元素的根节点合并的也一定程度的避免了结构变成链式,但是如果依次合并一些集合而不是合并独立的点它仍然会变长,不过由于是小集合元素的根变成大集合的根的子节点还好所以也就没超时,怪不得觉得少干了什么以后还是注意一下。

#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
struct wedge
{ int v1;
  int v2;
  int w;	
};
wedge g [200020];
wedge edges [200020];
void addedge(int v11,int v22,int ww,int i)
{  g[i].v1 =v11;
   g[i].w=ww;
   g[i].v2=v22;	
}
struct unionFindNode
{
   int parent;  
   bool root;   

   unionFindNode()
      {parent = 0; root = true;}
};
int dis[400];
bool cmp(wedge a, wedge b){
	return a.w < b.w;
}
class fastUnionFind
{
   public:
      fastUnionFind(int n)
      {// 初始化
        node = new unionFindNode[n+1];
        for(int i=0;i<n;i++)
        { node[i].parent=i;
          dis[i]=1;
		}
      }
      
      void unite(int rootA, int rootB)
      {int a=find(rootA),b=find(rootB);
       if(a==b)
       return;
       if(dis[a] >dis[b] )
	   {	swap(a,b);} 
		node[a].parent=b; 
		dis[a]=dis[a]+dis[b];  
	    dis[b]=dis[a]; 
       
      }
      
      int find(int e)
      {if(node[e].parent==e)
       return e;
       else 
       return find(node[e].parent);
         
      }
      
     private:
      unionFindNode *node;
};
      void kruskal( int n,int ee)
      {  
         fastUnionFind uf(n+5); 
         int k = 0; int i=0; 
         while (ee >0 &&k<=n-1 )
         { wedge x = g[i];  
            i++;
            ee--;
            int a = uf.find(x.v1);
            int b = uf.find(x.v2);
            if (a != b)
            {  edges[k++]=x;
               uf.unite(a,b);
            }  
         }    
	  	    cout<<edges[k-1].w<<endl;//最后一个是最长边 
      }
      

int  main(int  argc, char** argv) {
    
    int n,e=0;
    int m,root;
    cin>>n;
    cin>>m>>root;
    for(int i=0;i<m;i++)
    {int v1,v2,w;
    cin>>v1>>v2>>w;
    addedge(v1,v2,w,e);
    e++;
	
	}
	sort(g,g+e,cmp);
    kruskal(n,e); 
	return 0;
}
发布了9 篇原创文章 · 获赞 0 · 访问量 112

猜你喜欢

转载自blog.csdn.net/qq_45224092/article/details/105229604