第6週の割り当て

質問クリプトンゴールドベルトイースト

タイトルの説明

研究室にはコンピューター(1番)がありましたが、最近、クリプトニアンクルドンが2対Nの番号で研究室用にN-1台のコンピューターを購入しました。各コンピュータは、以前にインストールされたコンピュータにネットワークケーブルで接続されています。しかし、ググドンはネットワーク速度が遅すぎるのではないかと心配しており、i番目のコンピューターから他のコンピューターまでの最大ケーブル長を知りたいと思っていますが、貧しいググドンはつい最近まで宇宙線によるスマート攻撃を受けていません。助けてください。
ここに画像の説明を挿入
ヒント:サンプル入力はこの図に対応しています。この図から、コンピューター1から最も遠いコンピューターはコンピューター4であり、それらの間の距離は3であることがわかります。コンピュータNo. 4とコンピュータNo. 5は、コンピュータNo. 2から最も遠いポイントなので、答えは2です。コンピュータNo. 5は、コンピュータNo. 3から最も遠いので、コンピュータNo. 3の答えは3です。同様に、コンピューター4とコンピューター5の答えは4であると計算できます。input

入力ファイルには、テストデータの複数のセットが含まれています。テストデータの各セットについて、最初の行は整数N(N <= 10000)であり、N-1行、各行に2つの数値があり、i番目の行の2つの数値は、コンピューターiに接続された数を表しますコンピュータ番号とそれらの間のネットワークケーブルの長さ。ネットワークケーブルの全長は10 ^ 9以下で、各番号はスペースで区切られます。
出力:
テストデータの各セットについて、N行を出力します。i番目の行はコンピューターiの回答を表します(1 <= i <= N)。

Sample Input
5
1 1
2 1
3 1
1 1
Sample Output
3
2
3
4
4
アイデア

ここで必要な各ポイントから他のポイントまでの最長距離、ここでの最長距離は直径からの最も遠い距離にすることができます、問題は直径ポイントを見つける方法です、ここで最初にdfsを使用して任意のポイントの距離を見つけます遠点v1、次にdfsを実行してv1の最も遠い点v2を見つけます。v2を計算する過程で、各点までのv1の座標を取得しました。ここでも、dfsを使用して各点までのv2の距離を取得する必要があります。最後に大きい方の値を出力するだけ

コード
#include<iostream>
#include<stdio.h>
#include<vector>
#include<string.h>
#define MAx 10000
using namespace std;
struct edge
{
    int d,w;
   edge(int i,int j):d(i),w(j){};
};
vector<edge> p[MAx+1];
int t1,t2,v1,v2,n,mdis,dis[MAx+1],dis1[MAx+1];

bool vis[MAx+1];
void dfs(int s)
{
    vis[s]=1;  
    for(int i=0;i<p[s].size();i++)
    {
        if(!vis[p[s].at(i).d])
        {
            dis[p[s].at(i).d]=dis[s]+p[s].at(i).w;
            dfs(p[s].at(i).d);
        }
    } 
}
void dfss(int s)
{
    vis[s]=1;  
    for(int i=0;i<p[s].size();i++)
    {
        if(!vis[p[s].at(i).d])
        {
            dis1[p[s].at(i).d]=dis1[s]+p[s].at(i).w;
            dfss(p[s].at(i).d);
        }
    } 
}
int find()
{
    int ma=dis[1],t=1;
    for(int i=2;i<=n;i++)
    
        if(dis[i]>ma)
            ma=dis[i],t=i;
    return t;
}
int main()
{
    while ( scanf("%d",&n)!=EOF)
    {
        for(int i=2;i<=n;i++)
        {
            scanf("%d%d",&t1,&t2); 
            p[i].push_back({t1,t2});
            p[t1].push_back({i,t2});
        }
        memset(vis,0,sizeof(vis));
        dis[1]=0;
        dfs(1);
        v1=find();
        memset(vis,0,sizeof(vis));
        dis[v1]=0;
        dfs(v1);
        v2=find();
        dis1[v2]=0;
        memset(vis,0,sizeof(vis));
        dfss(v2);
        for(int i=1;i<=n;i++)
        printf("%d\n",dis[i]>dis1[i]?dis[i]:dis1[i]);
        for(int i=1;i<=n;i++)p[i].clear();
    }
    // system("pause");
    return 0;
}
 
まとめ

この質問はAですが、この直径はまだわかりませんが、それでも学ぶ必要があります。

質問Bには適切なマスクを使用してください。

タイトルの説明

「新しい冠状肺炎」と呼ばれる新しいコロナウイルス肺炎(コロナウイルス病2019、COVID-19)は、2019年の新しいコロナウイルス感染によって引き起こされる肺炎を指します。
感染者がグループに入る場合、このグループは隔離される必要があります!
リトルAの生徒は新しいクラウン感染症と診断され、マスクを着用していませんでした。Xiao Aと直接または間接的に接触しているすべての学生をすばやく見つけ、それらを隔離して感染拡大を防ぎます。ご存知のように、生徒のコミュニケーションは小さなグループに分けられ、生徒は同時に複数の小さなグループに参加できます。
それを解決するプログラムを書いてください!マスクを着用!テストデータの各セットについて、複数のデータセットを
入力し
ます。
最初の行は2つの整数nとm(n = m = 0は入力の終わりを示し、処理する必要はありません)、nは学生の数、mは学生グループの数です。0 <n <= 3e4、0 <= m <= 5e2
学生番号は0〜n -1A番号は0です。
次に、m行、各行には、小グループの要員の数である整数numがあります。次に、この小グループの生徒を表す整数がnum個あります。
出力
出力の数は、1行に1各データの出力に、答えを分離します

アイデア

これは典型的なマージ問題で、2つの配列がそれぞれ要素のカテゴリと数量を表していることを示しています。最初のpre配列はすべてそれ自体であり、sz配列はすべて1です
。マージ操作はマージされ、2人の生徒が以前にグループではない場合、iを表すグループがjのグループに追加され、jのサイズが更新されます。マージするには、0が配置されているグループの数を出力します。

コード
#include<stdio.h>
#include<string.h>
using namespace std;
int pre[30002],m,n,sz[30002];
int find(int i)
{
    return i==pre[i]?i:find(pre[i]);
}
bool merge(int i,int j)
{
    i=find(i);
    j=find(j);
    if(i==j)return 0;
    pre[i]=j;
    sz[j]+=sz[i];
    return 1;
}
int main()
{
    cin>>n>>m;
    while(!(n==0&&m==0))
    {
        for(int i=0;i<n;i++)
        {
            pre[i]=i;
            sz[i]=1;
        }        
        for(int i=0;i<m;i++)
        {
            int t,t1,t2=-1;
            cin>>t;
            for(int j=0;j<t;j++)
            {
                cin>>t1;
               // cout<<t1<<"  ";
                if(t2!=-1)
                    merge(t1,t2);
                else
                    t2=t1;
            } 
        }
        cout<<sz[find(0)]<<endl;
        cin>>n>>m;
    }
   // system("pause");
    return 0;
}

まとめ

この質問の並列チェックを書く簡単な方法は良いです。幸い、この質問は非常に特別です。良い組み合わせを得るには、最初に入力した数のグループに後で入力した数を追加するだけです。チェックの形式は、高さがとても高い。

C質問魔法のもの

タイトルの説明

ドンドンは彼の故郷に退屈していて、農業をしたいです。1からnまでの番号が付けられたnブロックの農地があります。農業
は必須です。ドンドンは魔術師であることはよく知られています。彼は一定のMPを消費してフィールドに魔法をかけ、黄河の水を空に飛ばすことができます。彼はまた、2つのフィールドの運河にポータルを構築するために一定量のMPを消費することができます。これにより、このフィールドはフィールドの水を参照します。(1 <= n <= 3e2)
黄河の空の水の消費量はWi、iは農地番号(1 <= Wi <= 1e5)
です。ポータルを確立するための消費量はPij、iおよびjは農地番号(1 <= Pij <= 1e5、Pij = Pji、Pii = 0)
東洞は、すべてのフィールドの灌漑
入力の最小消費量です。
ライン1:番号n
ライン2からラインn + 1:番号wi
ラインn + 2から行2n + 1:行列は、最も消費されていないMP のpij行列
出力
MP値です

样例

Input  
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0  
Output  
9
アイデア

この質問は空をスーパー原点として扱い、最小全域木問題として解くことができます。質問Bの組み合わせチェックは、判断を助けるために使用されます。選択が完了するか十分になるまで、エッジは一度ソートされて選択されます。 n-1ストップ。

コード
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;

struct edge
{
    int s,d,w;
    bool operator <(const edge&e)const{
        return w<e.w;
    }
};
int pre[305] ;
int find(int i)
{
    return i==pre[i]?i:find(pre[i]);
}
bool merge(int i,int j)
{
    i=find(i);
    j=find(j);
    if(i==j)return 0;
    pre[i]=j; 
    return 1;
}
edge e[50000];
int n,w,cnt,c,ans;
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;i++)
    {
        pre[i]=i;
    }
    for(int i=1;i<=n;i++)
    {
        e[cnt].d=i;
        cin>>e[cnt].w;
        e[cnt++].s=0;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        if(i>=j)
        {
            cin>>e[cnt].w;continue;
        }
        e[cnt].s=i;
        cin>>e[cnt].w;
        e[cnt++].d=j;
    }
    sort(e,e+cnt);
    edge t;
    for(int i=0;i<cnt&&c<n;i++)
    {
        t=e[i];
        if(merge(t.s,t.d))//成功
        {
            c++;
            ans+=t.w;
        }
    }
    cout<<ans<<endl;
   // system("pause");
    return 0;
}
まとめ

典型的な最小スパニングツリーの問題ですが、このスーパーオリジンの考え方はまだ学習されています。

質問Dデータセンター

タイトルの説明

ここに画像の説明を挿入

样例: 
input
4
5
1
1 2 3
1 3 4
1 4 5
2 3 8
3 4 2  
Output  
4
アイデア

この質問は扱いにくいですが、問題は非常に単純です。最小の全域木の最大のエッジが必要です。Kruskalによって追加された最後のエッジが答えです。ただし、ここでのユニオンチェックは単純ではありません。パス最適化を使用する必要があります

コード
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct edge
{
    int s,d,w;
    bool operator <(const edge&e)const{
        return w<e.w;
    }
};
int pre[50005] ;
int find(int p)
{
   // return i==pre[i]?i:find(pre[i]); 
            while(p != pre[p])
            {   //如果p元素的父亲指针指向的不是自己,说明p并不是集合中的根元
                //素,还需要一直向上查找和路径压缩
                //在find查询中嵌入一个路径压缩操作
                pre[p]=pre[pre[p]];
                //p元素不再选择原来的父亲节点,而是直接选择父亲节点的父亲节点来做为自己新的一个父亲节点
                //这样的操作使得树的层数被压缩了
                p=pre[p];
                //p压缩完毕后且p并不是根节点,p变成p新的父节点继续进行查找和压缩的同时操作
            }
            return p; 
}
bool merge(int i,int j)
{
    i=find(i);
    j=find(j);
    if(i==j)return 0;
    pre[i]=j; 
    return 1;
}
edge e[100005];
int n,m,root,w,cnt,c,ans,t1,t2,t3;
int main()
{
    scanf("%d%d%d",&n,&m,&root);
    for(int i=0;i<=n;i++)
    pre[i]=i;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&e[i].s,&e[i].d,&e[i].w);
    }  
    sort(e,e+m);
    edge t;
    for(int i=0;i<m&&c<n;i++)
    {
        t=e[i];
        if(merge(t.s,t.d))//成功
        {
            c++;
            if(c==n-1)ans=t.w;
        }
    }
    cout<<ans<<endl;
   // system("pause");
    return 0;
}
まとめ

パスを最適化する必要があることをどのように知っているかを尋ねないでください

元の記事を20件公開しました 賞賛されました3 訪問数453

おすすめ

転載: blog.csdn.net/qq_44893580/article/details/105282448