20170824图论选讲部分习题

1.车站分级

讲过啊,拓扑排序,每个停靠的车站向所有未停靠的车站连一条边,拓扑层数即可,小优化,每次删0度点的边时顺便统计一下删好后为0度点的边

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1005
using namespace std;
int to[maxn][maxn],point[maxn],Map[maxn][maxn],x[maxn],v[maxn],a[maxn],b[maxn];
int ans=0,n,m;
void work()
{
    for(int i=1;i<=n;i++)
    if(!v[i]) point[++point[0]]=i;
    while(point[0])
    {
        ans++;
        while(point[0])
        {
            int k=point[point[0]];point[0]--;
            for(int i=1;i<=to[k][0];i++)
            {
                v[to[k][i]]--;
                if(!v[to[k][i]]) x[++x[0]]=to[k][i];
            }
        }
        for(int i=1;i<=x[0];i++)
        point[i]=x[i];
        point[0]=x[0];
        x[0]=0;
    }
    printf("%d
",ans);
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&a[0]);
        b[0]=0;
        for(int i=1;i<=a[0];i++) scanf("%d",&a[i]);
        for(int i=1;i<a[0];i++)
            for(int j=a[i]+1;j<a[i+1];j++)
            b[++b[0]]=j;
        for(int i=1;i<=a[0];i++)
            for(int j=1;j<=b[0];j++)
            if(!Map[a[i]][b[j]])
            {
                Map[a[i]][b[j]]=1;
                v[b[j]]++;
                to[a[i]][++to[a[i]][0]]=b[j];
            }    
    }
    work();
}

2.种树,这个我写过题解了

3.秦始皇的国家道路。先枚举选的是那条边,因为cnt总值最小肯定更优,我们用Prim求最小生成树可以接近最优值,考虑到加上选的边后的最小生成树是由原最小生成树换1条边的正确性可由Kruskal来证明吧。就是把最小生成树中u,v中的那条路径中最大的一条边换成枚举的那条边。

#include<cstdio> 
#include<cmath> 
#include<algorithm> 
using namespace std; 
struct node{ 
    int x,y; 
    double val; 
}a[2000005]; 
int num1,num,f1,root; 
int f[2000005],p[2000005],flag[2000005]; 
double dis[1005][1005],x[2000005],y[2000005]; 
int v[2000005],next[2000005],head[10005],vis[10005]; 
double v1[2000005]; 
int find(int u) 
{ 
    if (f[u]!=u) f[u]=find(f[u]); 
    return f[u]; 
} 
void add(int a,int b,double val) 
{ 
    num1++; 
    v[num1]=b; 
    v1[num1]=val; 
    next[num1]=head[a]; 
    head[a]=num1; 
} 
bool cmp(node a,node b) 
{ 
    return a.val<b.val; 
} 
void dfs(int u,double val) 
{ 
    dis[root][u]=val; 
    vis[u]=f1; 
    for (int i=head[u]; i; i=next[i]) 
    { 
        int V=v[i]; 
        if (vis[V]!=f1) dfs(V,max(val,v1[i])); 
    } 
} 
int main() 
{ 
int asdasdasdasd;
    int t; 
    scanf("%d",&t); 
    while (t--) 
    { 
        num1=0; 
        num=0; 
        int n; 
        scanf("%d",&n); 
        for (int i=1; i<=n; i++) 
            head[i]=0; 
        for (int i=1; i<=n; i++) 
            scanf("%lf%lf%d",&x[i],&y[i],&p[i]); 
        for (int i=1; i<=n; i++) 
            for (int j=i+1; j<=n; j++) 
            { 
                double dis=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); 
                num++; 
                a[num].x=i; 
                a[num].y=j; 
                a[num].val=sqrt(dis); 
                /*num++; 
                a[num].x=j; 
                a[num].y=i; 
                a[num].val=sqrt(dis);*/
            } 
        sort(a+1,a+num+1,cmp); 
        for (int i=1; i<=n; i++) 
            f[i]=i; 
        double ans=0; 
        for (int i=1; i<=num; i++) 
        { 
            flag[i]=0; 
            int fx=find(a[i].x); 
            int fy=find(a[i].y); 
            if (fx!=fy) 
            { 
                f[fx]=fy; 
                //f[fx]=find(fx); 
                ans+=a[i].val; 
                flag[i]=1; 
            } 
        } 
        for (int i=1; i<=num; i++) 
            if (flag[i])  
            { 
                add(a[i].x,a[i].y,a[i].val); 
                add(a[i].y,a[i].x,a[i].val); 
            } 
        f1=0; 
        for (int i=1; i<=n; i++) 
        { 
            f1++; 
            root=i; 
            dfs(i,0); 
        } 
        double ans1=0; 
        for (int i=1; i<=n; i++) 
            for (int j=i+1; j<=n; j++) 
                if ((p[i]+p[j])/(ans-dis[i][j])>ans1) ans1=(p[i]+p[j])/(ans-dis[i][j]); 
        printf("%.2f
",ans1); 
    } 
    return 0; 
} 
    

4.受欢迎的奶牛

Tarjan求强连通分量缩点

求度为0的个数,如果大于等于2个,无解,不然输出度为0的强连通分量的size

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack> 
#define maxn 100100
using namespace std;
stack<int> S;
struct note{
    int u,v;
}edge[maxn];
bool instack[maxn];
int to[maxn*2],id[maxn],Time,ans,num,sc,head[maxn],visit[maxn],next[maxn*2],low[maxn],dfn[maxn],n,m,size[maxn];
void make_way(int u,int v)
{
    to[++num]=v;
    next[num]=head[u];
    head[u]=num;
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++Time;
    instack[u]=1;
    S.push(u);
    for(int ed=head[u];ed;ed=next[ed])
    {
        if(!dfn[to[ed]])
        {
            tarjan(to[ed],u);
            low[u]=min(low[u],low[to[ed]]);
        }else
        if(instack[to[ed]])
        low[u]=min(low[u],dfn[to[ed]]);
    }
    //cout<<u<<' '<<low[u]<<' '<<dfn[u]<<endl;
    if(low[u]==dfn[u])
    {
        sc++;
        int v;
        do{
            
            v=S.top();
            S.pop();
            instack[v]=0;
            id[v]=sc;
            size[sc]++; 
        }while(v!=u&&!S.empty());
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d",&edge[i].u,&edge[i].v);
        make_way(edge[i].u,edge[i].v);
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])
    {
        tarjan(i,0);
    }
    for(int i=1;i<=m;i++)
    if(id[edge[i].u]!=id[edge[i].v])
    visit[id[edge[i].u]]++;
    bool flag=0;
    for(int i=1;i<=sc;i++)
    {
        if(!visit[i])
        {
            if(flag)
            {    
                cout<<0<<endl;
                return 0;
            }
            flag=1;
            ans=i;
        }
    }
    printf("%d
",size[ans]);
 } 

6.矿场搭建

WA10分,待改

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring> 
#define ll long long
using namespace std;
int n,m,cnt,num,tot,son_num,ans1,Time,T,cases,root;
ll ans2;
int head[500005],dfn[500500],low[500005],vis[500005];
bool cut[500005];
int Next[1000005],to[1000005];
void make_way(int u,int v)
{
    to[++num]=v;
    Next[num]=head[u];
    head[u]=num;
 } 
 void tarjan(int u,int fa_edge)
 {
     low[u]=dfn[u]=++Time;
     for(int edge=head[u];edge;edge=Next[edge])
     if(edge^1!=fa_edge)
     {
         int v=to[edge];
         if(!dfn[v])
         {
             tarjan(v,u);
             low[u]=min(low[u],low[v]); 
             if(low[v]>=dfn[u])
             {
                 if(u==root) son_num++;else cut[u]=1;
             }
         }else
        {
            low[u]=min(low[u],dfn[v]);
         } 
     }
 }
 void dfs(int u)
 {
     vis[u]=T;
     if(cut[u]) return;
     cnt++;
     for(int edge=head[u];edge;edge=Next[edge])
     {
         if(cut[to[edge]]&&vis[to[edge]]!=T) num++,vis[to[edge]]=T;
         if(!vis[to[edge]]) dfs(to[edge]);
     }
  } 
int main()
{
    int Case=0;
    while(~scanf("%d",&m)&&m)
    {
        Case++;
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        memset(low,0,sizeof(low));
        memset(cut,0,sizeof(cut));
        Time=num=n=ans1=T=0;
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            n=max(n,max(u,v));
            make_way(u,v);
            make_way(v,u);
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])tarjan(root=i,0);
            if(son_num>=2)
            cut[root]=1;
            son_num=0;
        }
        ans1=0;
        ans2=1;
        for(int i=1;i<=n;i++)
            if(!vis[i]&&!cut[i])
            {
                T++;cnt=num=0;
                dfs(i);
                if(!num) ans1+=2,ans2*=cnt*(cnt-1)/2;
                if(num==1) ans1++,ans2*=cnt;
            }
        printf("Case %d: %d %lld
",Case,ans1,ans2);
    }
    
}
原文地址:https://www.cnblogs.com/dancer16/p/7436589.html