2014新生暑假个人排位赛06 -444. 爱好和平 (数组模拟邻接表+dfs)

时间限制 1000 ms  内存限制 65536 KB

题目描述

在星际时代,每个帝国都靠着贸易路线连接着各个联盟星球,这些贸易路线都是双向可达的。一个帝国的综合实力由他贸易连接着的联盟星球数决定。
学姐作为Mays帝国的领袖,长期与Luke帝国保持着敌对关系,爱好和平的学姐希望结束长达几个世纪的战争,于是找实验室定做了一颗代号小苹果的炸弹,可以定点摧毁一颗星球,这颗星球被毁后,与它相连的全部贸易就都被切断了,这样Luke帝国可能就被切断为一个小联盟,他们就再也不会对学姐的地位构成威胁啦~
经过调查,Luke帝国为了节约经费,他的联盟星之间都有且仅有一条直接或间接的贸易通路。
现在给出Luke帝国的贸易线路,学姐想知道摧毁哪一颗行星可以使得分裂后的若干Luke联盟威胁最大的分部最小。

输入格式

输入有多组数据,组数不大于10组。每一组开头一行为n,m,表示Luke帝国的联盟星球数量,和贸易关系数,接下来m行,每行两个整数u,v,表示星球u,v之间存在直接的贸易路线,1<=u,v<=n,1<=n,m<=100000

输出格式

输出一个数表示推荐学姐摧毁的星球,如果有多解,输出编号最小的一个。

输入样例

5 4
1 2
1 3
1 4
4 5

输出样例

1  
首先是分析题意,根据题意可知目标是求每个节点所连接的(两个子节点和的最大数量)与(其父亲节点所连的另一边的节点数)的最大值dp[u],每个节点都得到这样的一个dp[u]值,然后遍历比较找到所有点的max值的最小值,然后选取该点。
包括知识点:用数组模拟邻接表+dfs
<span style="font-size:14px;">#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn=100005;
const int maxe=200010;
int head[maxn];
int n,m;
int u,v;
int dp[maxn];
int num[maxn];
int cnt=1;
struct
{
   int to,next;
}e[maxe];
void init()
{
    for(int i=0;i<=n;i++)
    {
        head[i]=0;
        dp[i]=0;
        num[i]=0;
    }
}
 
 void add(int u,int v)
 {
     e[cnt].to=v;//第cnt条边;
     e[cnt].next=head[u];//head数组的相当于下标的作用;而数组的下标u表示以u为起点;
     head[u]=cnt++;
 }
int dfs(int u,int fa)//搜索是从u点出发的,若u连有x条边就dfs一次
{
    num[u]=1;
    for(int i=head[u];i!=0;i=e[i].next)//注意循环条件,head的值是cnt赋给的所以head也是相当于技术,若其等于0,表示最初的状态,即以该点为起始点的边已经遍历完毕;
    {
        int v=e[i].to;
        if(v==fa) continue;<span style="font-family: Arial, Helvetica, sans-serif;">//直到找到指向fa为止;</span>

        else num[u]+=dfs(v,u);//若没有找到fa则再往下继续搜索,每一次dfs都是搜一个点的所有儿子,所以dfs一次的返回值是儿子数目。
    }
    dp[u]=n-num[u];//除了他和所有儿子以外剩的;
    for(int i=head[u];i!=0;i=e[i].next)//再遍历一遍;
    {
        int v=e[i].to;
        if(v==fa) continue;
        else dp[u]=max(num[v],dp[u]);
    }
    return num[u];
}
 
int main()
{
    while (scanf("%d%d",&n,&m)==2)
    {
        init();
        cnt=1;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1,0);
        int ans=10000000;
        for(int i=1;i<=n;i++)
            ans=min(ans,dp[i]);
        for(int i=1;i<=n;i++)
        {
            if(ans==dp[i])
            {
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}</span>





网上看来的,讲的挺好,其实后来发现这个其实数组的名字就是指针的概念,例如
: next[i]=first[ u [ i ] ]就是i->next=u[i]->first.
  1. int main()  
  2. {  
  3.     int i,j,n,m,t,c;  
  4.     int first[MAXN];  
  5.     int u[MAXN],v[MAXN],w[MAXN],next[MAXN];  
  6.     scanf("%d%d",&n,&m);  
  7.     for(i=0;i<=n;i++) first[i]=-1;  
  8.     for(i=0;i<m;i++)  
  9.     {  
  10.         scanf("%d%d",&u[i],&v[i]);//u是弧尾,v弧头   
  11.         next[i]=first[u[i]];//就这万恶的两行   
  12.         first[u[i]]=i;//短小精悍!   
  13.     }  
  14.     //后面为自己理解后添加的。   
  15.     for(i=1;i<=n;i++)  
  16.     {  
  17.         if(first[i]==-1)  
  18.         {  
  19.             printf("没有以点<%d>为起点的邻接表。\n",i);  
  20.             continue;  
  21.         }  
  22.         printf("以点<%d>为起点的邻接表:\n",i);  
  23.         for(j=first[i];j!=-1;j=next[j])  
  24.         {  
  25.             printf("<%d  %d>    ",i,v[j]);  
  26.         }  
  27.         printf("\n\n");  
  28.     }  
  29.     return 0;  

这个可以用来读入有向图(最好是稀疏)的边列表,然后建立邻接表。
next[i]=first[ u [ i ] ] 表示第i条边的下一条边是first[ u [ i ] ];

first[ u [ i ] ]=i 就是把节点u[i] 的链表头指向第i条边。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值