【THOI 2012】 社交网络结构洞

来源:互联网 发布:unity3d 粒子特效爆炸 编辑:程序博客网 时间:2024/05/16 11:19

A1364. 社交网络结构洞

首先我们将题目所求转化一下,变成求相邻的三个点对答案的贡献。

  • 先说我65分的做法
    • 枚举不相邻的两个点,然后枚举有几个点能成为他俩的中间点为cnt,如果cnt==0cnt>1,这两个点显然对答案没有贡献,那么把cnt==1的两个点加入询问中,并记录中间点。
      (其实相当于缩小了询问范围)
    • 之后,对于能作为中间点的每一个点,分别去掉他;然后对于所询问的点跑单源最短路;那么他两边的点对答案的贡献就是d[i][j]2
#include <iostream>#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <cstdlib>#include <queue>#include <vector>#define inf 0x3f3f3f3f#define M 2005#define pb push_backusing namespace std;vector<int> q[M][M];int tot,d[M],v[M],ans[M],inq[M],n,m,D[M],a[M][M],h[M];struct edge{    int y,ne;}e[M*100];void SPFA(int s,int k){    for (int i=1;i<=n;i++)        d[i]=inf;    d[s]=0;    queue<int> q;    q.push(s);    inq[s]=1;    while (!q.empty())    {        int x=q.front();        q.pop();        inq[x]=0;        for (int i=h[x];i;i=e[i].ne)        {            int y=e[i].y;            if (y==k) continue;            if (d[y]>d[x]+1)            {                d[y]=d[x]+1;                if (!inq[y])                    q.push(y),inq[y]=1;            }        }    }}void Addedge(int x,int y){    e[++tot].y=y;    e[tot].ne=h[x];    h[x]=tot;}void spfa(int s){    for (int i=1;i<=n;i++)        d[i]=D[i]=inf,inq[i]=0,v[i]=0;    d[s]=D[s]=0;    queue<int> q;    q.push(s);    inq[s]=1;    while (!q.empty())    {        int x=q.front();        inq[x]=0;        q.pop();        for (int i=h[x];i;i=e[i].ne)        {            int y=e[i].y;            if (d[y]>d[x]+1)            {                if (d[x]==1&&!v[y])                {                    v[y]=x;                    continue;                }                d[y]=d[x]+1;                if (v[y]!=x) D[y]=d[y];                if (!inq[y])                    inq[y]=1,q.push(y);            }        }    }    for (int i=1;i<=n;i++)        if (v[i]&&d[i]>2)            ans[v[i]]+=(d[i]-2);}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++)    {        int x,y;        scanf("%d%d",&x,&y);        Addedge(x,y);        Addedge(y,x);        a[x][y]=a[y][x]=1;    }    for (int i=1;i<=n;i++)    {        for (int j=1;j<i;j++)            {                if (a[i][j]) continue;                int cnt=0,p;                for (int k=1;k<=n;k++)                {                    if (a[i][k]&&a[j][k])                        p=k,cnt+=1;                }                if (cnt==1)                    q[p][i].pb(j);            }    }    for (int i=1;i<=n;i++)    {        for (int j=1;j<=n;j++)            if (q[i][j].size())            {                SPFA(j,i);                for (int k=0;k<q[i][j].size();k++)                    ans[i]+=(d[q[i][j][k]]-2);            }    }    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]);    cout<<endl;    /*    for (int i=1;i<=n;i++)        spfa(i);    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]/2);    */    return 0;}

(注释掉的部分是我一开始写95分做法,写的有漏洞。。)

  • 再说95分的做法:

    • 我们可以枚举三元组中的一头s,跑SPFA。

    • 对于直接与s相邻的点x,他能拓展出与s距离为2的点y,我们需要记录从s出发不经过x到达y的最短路,加入对x的贡献。(最后所有答案都/2

    • 这个如何实现呢?

    • 距离d数组多记录一维d[i][0],d[i][1]分别表示经过x和不经过x的最短路(这样做不会漏下,因为如果经过一个以上的x对答案没有贡献),from[i][0]=x,from[i][1]x,然后像跑SPFA一样求即可。

    • 注意只要一求出d[i][j],之后一定不会更新了!因为队列中的d[][]是不降的!
#include <iostream>#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <cstdlib>#include <queue>#include <vector>#define mp make_pair#define pa pair<int,int>#define fi first#define se second#define inf 0x3f3f3f3f#define M 2005#define pb push_backusing namespace std;vector<int> q[M][M];int from[M][2],d[M][2];struct data{    int v,k;};int tot,v[M],ans[M],inq[M],n,m,D[M],a[M][M],h[M];struct edge{    int y,ne;}e[M*100];void Addedge(int x,int y){    e[++tot].y=y;    e[tot].ne=h[x];    h[x]=tot;}void bfs(int s){    for (int i=1;i<=n;i++)        from[i][0]=from[i][1]=-1;    d[s][0]=d[s][1]=from[s][1]=from[s][0]=0;    queue<pa> q;    for (int i=h[s];i;i=e[i].ne)    {        int y=e[i].y;        from[y][0]=y;        d[y][0]=1;        q.push(mp(y,0));    }    while (!q.empty())    {        pa x=q.front();        q.pop();        for (int i=h[x.fi];i;i=e[i].ne)        {            int y=e[i].y;            if (from[y][0]==-1)            {                from[y][0]=from[x.fi][x.se];                d[y][0]=d[x.fi][x.se]+1;                q.push(mp(y,0));            }            else if (from[y][1]==-1&&!a[y][s]&&from[y][0]!=from[x.fi][x.se])            {                from[y][1]=from[x.fi][x.se];                d[y][1]=d[x.fi][x.se]+1;                q.push(mp(y,1));            }        }    }    for (int i=h[s];i;i=e[i].ne)    {        int y=e[i].y;        for (int j=h[y];j;j=e[j].ne)            if (e[j].y!=s&&from[e[j].y][0]==y)                ans[y]+=(d[e[j].y][1]-d[e[j].y][0]);    }}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++)    {        int x,y;        scanf("%d%d",&x,&y);        Addedge(x,y);        Addedge(y,x);        a[x][y]=a[y][x]=1;    }    for (int i=1;i<=n;i++)        bfs(i);    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]/2);    return 0;}
  • 膜拜了ydc的代码,加入了常数优化的100分代码
    • 在95分做法的基础上,可以先判断这个s作为三元组的一头是否会对答案产生贡献
    • 如何判断呢?
    • 用到了65分做法中的思想,如果两点的中间点个数1,这两个点对答案就没有贡献,然后用count函数统计一下这个点作为一头是否有cnt==1的,如果没有就不以这个点为起点进行dfs了。
#include <iostream>#include <algorithm>#include <cmath>#include <cstdio>#include <cstring>#include <cstdlib>#include <queue>#include <vector>#define mp make_pair#define pa pair<int,int>#define fi first#define se second#define inf 0x3f3f3f3f#define M 2005#define pb push_backusing namespace std;vector<int> q[M][M];int from[M][2],d[M][2],cnt[M][M];struct data{    int v,k;};int tot,v[M],ans[M],inq[M],n,m,D[M],a[M][M],h[M];struct edge{    int y,ne;}e[M*100];void Addedge(int x,int y){    e[++tot].y=y;    e[tot].ne=h[x];    h[x]=tot;}void bfs(int s){    for (int i=1;i<=n;i++)        from[i][0]=from[i][1]=-1;    d[s][0]=d[s][1]=from[s][1]=from[s][0]=0;    queue<pa> q;    for (int i=h[s];i;i=e[i].ne)    {        int y=e[i].y;        from[y][0]=y;        d[y][0]=1;        q.push(mp(y,0));    }    while (!q.empty())    {        pa x=q.front();        q.pop();        for (int i=h[x.fi];i;i=e[i].ne)        {            int y=e[i].y;            if (from[y][0]==-1)            {                from[y][0]=from[x.fi][x.se];                d[y][0]=d[x.fi][x.se]+1;                q.push(mp(y,0));            }            else if (from[y][1]==-1&&!a[y][s]&&from[y][0]!=from[x.fi][x.se])            {                from[y][1]=from[x.fi][x.se];                d[y][1]=d[x.fi][x.se]+1;                q.push(mp(y,1));            }        }    }    for (int i=h[s];i;i=e[i].ne)    {        int y=e[i].y;        for (int j=h[y];j;j=e[j].ne)            if (e[j].y!=s&&from[e[j].y][0]==y)                ans[y]+=(d[e[j].y][1]-d[e[j].y][0]);    }}void Prepare(){    for (int i=1;i<=n;i++)        for (int j=h[i];j;j=e[j].ne)            for (int k=h[i];k;k=e[k].ne)                if (e[j].y!=e[k].y)                    cnt[e[j].y][e[k].y]++;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++)    {        int x,y;        scanf("%d%d",&x,&y);        Addedge(x,y);        Addedge(y,x);        a[x][y]=a[y][x]=1;    }    Prepare();    for (int i=1;i<=n;i++)        if (count(cnt[i]+1,cnt[i]+1+n,1))            bfs(i);    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]/2);    return 0;}
2 0
原创粉丝点击