日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【THOI 2012】 社交网络结构洞

發布時間:2024/1/18 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【THOI 2012】 社交网络结构洞 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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_back using 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_back using 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_back using 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; }

總結

以上是生活随笔為你收集整理的【THOI 2012】 社交网络结构洞的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。