【THOI 2012】 社交网络结构洞
来源:互联网 发布:unity3d 粒子特效爆炸 编辑:程序博客网 时间:2024/05/16 11:19
A1364. 社交网络结构洞
首先我们将题目所求转化一下,变成求相邻的三个点对答案的贡献。
- 先说我65分的做法
- 枚举不相邻的两个点,然后枚举有几个点能成为他俩的中间点为
cnt ,如果cnt==0或者cnt>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
- 【THOI 2012】 社交网络结构洞
- 【THOI 2012】 水位
- 社交网络
- “社交网络”
- 社交网络
- 社交网络
- 推荐算法:社交化网络:社交网络
- 社交网络 知识搜索
- 社交网络的魅力
- 社交网络的魅力
- 社交网络的魅力
- 社交网络的魅力
- 网络社交英语漫谈
- 社交网络的“悖论”!?
- 社交网络数据挖掘
- 社交网络博弈论
- 社交网络数据挖掘
- 又一个社交网络-highlight
- activity和service通信
- Multiple Threads: Word Frequency
- HDU 2602 解题报告
- Android中点击按钮后隐藏输入法
- BCD 十六进制 十进制 相关转换
- 【THOI 2012】 社交网络结构洞
- .Net与JavaMVC思想比较
- JavaEE之捣蛋的Filter
- Linux tcpdump
- 【BZOJ 1857】 [Scoi2010]传送带
- 【ThinkingInJava】34、java的动态代理(2)
- 虚函数和纯虚函数的作用与区别
- 编写binder服务端和客户端存在两个问题
- 匠心