QFNU 天梯赛练习 1 补题

7-14 社交集群(30)

题意

给定 (n) 个人的爱好,求这 (n) 个人一共组成了多少个圈子,每个圈子的大小。

题解

使用并查集维护即可。

代码

#include <bits/stdc++.h>
using namespace std;

int p[1005], n, a[1005];

int Find(int x){
    if(p[x] != x) p[x] = Find(p[x]);
    return p[x];
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++ ) p[i] = i;
    for(int i = 1; i <= n; ++ i) {
        int k, h;
        scanf("%d:", &k);
        while(k --) {
            cin >> h;
            if(a[h]) p[Find(i)] = Find(a[h]);
            else a[h] = i;
        }
    }
    map<int, int> cnt;
    for(int i = 1; i <= n; ++ i)
        cnt[Find(i)] ++;
    vector<int> v;
    for(auto x : cnt)
        v.push_back(x.second);
    sort(v.begin(), v.end(), greater<int>());
    cout << v.size() << '
' << v[0];
    for(int i = 1; i < v.size(); ++ i)
        cout << ' ' << v[i];
    cout << endl;
    return 0;
}

垃圾箱分布(30)

对每一个垃圾桶选择点都进行 Dijkstra,在 dis 数组的最大值不大于 dis 的情况下,选择 dis 的数组的最小值最大的,如果最小值一样就选择和最小的。

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int n,k,m,ds;
int e[1205][1205];
bool v[1205];
int d[1205];
int kk=1;
struct node
{
    int bh;
    double p;
    int h;
    int zd;
}a[15];
bool cmp(node x,node y)
{
    if(x.zd==y.zd)
    {
        if(x.p==y.p)
            return x.bh<y.bh;
        else return x.p<y.p;
    }
    else return x.zd>y.zd;//最短距离要最长
}
void dijstra(int s)
{
    int i;
    memset(v,0,sizeof(v));
    v[s]=1;
    int zd=inf;
    for(i=1;i<=n+m;i++) 
    {
        d[i]=e[s][i];
        if(!v[i]&&i<=n&&d[i]<zd)//条件要写全
            zd=d[i];
    }
    while(1)
    {
        int k=-1;
        int mm=inf;
        for(i=1;i<=n+m;i++)
        {
            if(!v[i]&&d[i]<mm)
            {
                k=i;
                mm=d[i];
            }
        }
        if(k==-1) break;
        v[k]=1;
        for(i=1;i<=n+m;i++)
        {
            if(d[i]>d[k]+e[k][i])
            {
                d[i]=d[k]+e[k][i];
                if(!v[i]&&i<=n&&d[i]<zd)
                    zd=d[i];//把最短的距离找出来
            }
        }
    }
    int ss=0;
    for(i=1;i<=n;i++)
    {
        if(d[i]>ds) break;//最短路径超出范围的不要
        else ss+=d[i];
    }
    if(i==n+1)
    {
        a[kk].bh =s-n;
        a[kk].h=ss;
        a[kk].zd=zd;
        a[kk++].p=ss*1.0/n;
    }
}

int main()
{
   cin>>n>>m>>k>>ds;
   int i,j;
   for(i=1;i<=n+m;i++)
       for(j=1;j<=n+m;j++)
       {
           if(i==j) e[i][j]=0;
           else e[i][j]=inf;
       }
   for(i=1;i<=k;i++)
   {
       string a,b;//G的处理
       int z;
       cin>>a>>b>>z;
       int x=0,y=0;
       if(a[0]!='G') 
       {
           int l=a.length ();
           for(int i=0;i<l;i++)
           {
               x=x*10+a[i]-'0';
           }
       }
       else 
       {
          int l=a.length ();
           for(int i=1;i<l;i++)
           {
               x=x*10+a[i]-'0';
           }
            x+=n;
       }

       if(b[0]!='G') 
       {
            int l=b.length ();
           for(int i=0;i<l;i++)
           {
               y=y*10+b[i]-'0';
           }
       }
       else 
       {
           int l=b.length ();
           for(int i=1;i<l;i++)
           {
               y=y*10+b[i]-'0';
           }
           y+=n;
       }
       if(e[x][y]>z)
       {
           e[x][y]=z;
           e[y][x]=z;
       }
   }
   for(int i=n+1;i<=m+n;i++)//遍历每一个垃圾箱
   {
       dijstra(i);
   }
   if(k==1) cout<<"No Solution";
   else
   {
       sort(a+1,a+kk,cmp);//排个序,是kk
       if(a[1].bh==0)  cout<<"No Solution";
       else
       {
           cout<<"G"<<a[1].bh<<endl;
            printf("%.1lf",a[1].zd*1.0);cout<<" ";
           printf("%.1lf",a[1].p);
       }
   }
   return 0;
}

地铁一日游 (30)

这道题的结点数较少,所以我们可以用Floyed求出最短路径。
然后我们对于每一个站点i,都求出在花费相同时可以到达的最远的站点,把这些站点都作为i的候选站点。
接着对于每一次查询,我们用一次dfs把从开始结点出发可以到达的所有结点都打上标记,接着我们只要输出标记等于本次查询序号的结点即可。
注意坐地铁是可以来回往返的,所以要用dfs。

#include<stdio.h>
#include<iostream>
#include<map>
#include<vector>
#define MAX 205
#define INF 0x3f3f3f3f
using namespace std;

struct station{
    int visit,ends;
    station(){
        visit=ends=0;
    }
    vector<int> res;//所有可到达的站
}sta[MAX];

int mp[MAX][MAX];
int n,m,k;

void floyed(){//Floyed求最短路径
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i!=j&&mp[i][j]>mp[i][k]+mp[k][j]){
                    mp[i][j]=mp[i][k]+mp[k][j];
                }
            }
        }
    }
}

void dfs(int i,int vis){
    for(int j=0;j<sta[i].res.size();j++){
        int t=sta[i].res[j];
        if(sta[t].visit!=vis){
            sta[t].visit=vis;
            dfs(t,vis);
        }
    }
}

int main(){
    for(int i=0;i<MAX;i++){
        for(int j=0;j<MAX;j++){
            mp[i][j]=INF;
        }
    }
    scanf("%d%d%d",&n,&m,&k);
    int a,b,len;
    for(int i=0;i<m;i++){
        scanf("%d",&a);
        sta[a].ends=1;
        do{
            scanf("%d%d",&len,&b);
            if(len<mp[a][b]) mp[a][b]=mp[b][a]=len;
			a=b;
		}while(getchar()!='
');
		sta[a].ends=1;
    }
    floyed();//求出最短路径
    for(int i=1;i<=n;i++){//对于每个站而言,寻找每个费用的最远距离,并将结果存入res中
        map<int,int> m1;
        for(int j=1;j<=n;j++){
            if(mp[i][j]!=INF&&mp[i][j]>m1[mp[i][j]/k+2]){
                m1[mp[i][j]/k+2]=mp[i][j];
            }
        }
        for(int j=1;j<=n;j++){
            if(mp[i][j]==m1[mp[i][j]/k+2]||(i!=j&&mp[i][j]!=INF&&sta[j].ends==1)){
               sta[i].res.push_back(j);
            }
        }
    }
    int q,start;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d",&start);
        sta[start].visit=i;//打上标记i
        dfs(start,i);//将所有可能的站都打上标记i
        int flag=0;
        for(int j=1;j<=n;j++){
            if(sta[j].visit==i){
                printf("%s%d",flag==0?"":" ",j);
                flag=1;
            }
        }
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/DariusOrz/p/13796787.html