连通性(相关练习)

文章目录

  • NC20603 [ZJOI2007]最大半连通子图
    • 题目:
    • 题解:
    • 代码:
  • NC50403 嗅探器
    • 题目:
    • 题解:
    • 代码:
  • NC51269 Network of Schools
    • 题目:
    • 题解:
    • 代码:
  • NC106972 Cow Ski Area
    • 题目:
    • 题解:
    • 代码:
  • NC51307 Redundant Paths
    • 题目:
    • 题解:
    • 代码:
  • NC20099 [HNOI2012]矿场搭建
    • 题目:
    • 题解:
    • 代码:
  • NC19981 [HAOI2010]软件安装
    • 题目:
    • 题解:
  • NC51267 Knights of the Round Table
    • 题目:
    • 题解:
  • poj1515 NC106112 Street Directions
    • 题目:
    • 题解:
  • NC51319 King's Quest
    • 题目:
    • 题解:
    • 代码:

NC20603 [ZJOI2007]最大半连通子图

题目:

• 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:u,v∈V,满足u→v或v→u,即对于图中任意 两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。
• 若G’=(V’,E’)满足V’∈V,E’是E中所有跟V’有关的边, 则称G’是G的一个导出子图。
• 若G’是G的导出子图,且G’半连通,则称G’为G的半连通子图。
• 若G’是G所有半连通子图 中包含节点数最多的,则称G’是G的最大半连通子图。
• 给定一个有向图G,请求出G的最大半连通子图拥有的节点数K ,以及不同的最大半连通子图
的数目C。由于C可能比较大,仅要求输出C对X的余数。

题解:

• 如果两点互相可以到达,那么它们必是半连通图,所以考虑先Tarjan缩点,接着去除重边重新建图,你会发现,在这个有向无环图(DAG)中,半连通子图都是一条链(可以举反例试试,这条链不可能有分支,否则将有两点无法抵达另一方)
• 于是,G的最大半连通子图拥有的节点数K就是最长链长度,不同的最大半连通子图的数目就是最长链个数。
• 最长链可以直接用拓扑排序(topo),最长链个数用一个类似DP的方法,用f【i】表示以 i为终点的方案数,那么f【i】就等于满足距离为起点到 i 的临时最短距离的点的 f 的和。然后查找距离等于最长链的点,答案为它们的方案数之和

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10,maxm=1e6+10;
struct edge
{int u,v,nxt;
}e[maxm],ee[maxm];
int head[maxn],js,headd[maxn],jss;
void addage(edge e[],int head[],int &js,int u,int v)
{e[++js].u=u;e[js].v=v;e[js].nxt=head[u];head[u]=js;
}
int dfn[maxn],low[maxn],cnt,st[maxn],top,lt[maxn],lts,ltn[maxn];
void  tarjan(int u)
{dfn[u]=low[u]=++cnt;st[++top]=u;for(int i=head[u];i;i=e[i].nxt){int v=e[i].v;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(!lt[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){lt[u]=++lts;ltn[lts]++;while(st[top]!=u)lt[st[top--]]=lts,ltn[lts]++;--top;}
}
int n,m,x;
int f[maxn],ff[maxn];
int cd[maxn],rd[maxn];
int maxd,maxf;
int pc[maxn];
queue<int>q;
void dfs()
{while(!q.empty()){int u=q.front();q.pop();maxd=max(maxd,f[u]);for(int i=headd[u];i;i=ee[i].nxt){int v=ee[i].v;rd[v]--;if(rd[v]==0)q.push(v);if(pc[v]==u)continue;if(f[u]+ltn[v]>f[v]){f[v]=f[u]+ltn[v];ff[v]=ff[u];}else if(f[u]+ltn[v]==f[v]){ff[v]=(ff[u]+ff[v])%x;}pc[v]=u;}}
}
int main()
{scanf("%d%d%d",&n,&m,&x);for(int u,v,i=1;i<=m;++i){scanf("%d%d",&u,&v);addage(e,head,js,u,v);}for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i);for(int u=1;u<=n;++u)for(int i=head[u];i;i=e[i].nxt)if(lt[e[i].u]!=lt[e[i].v])addage(ee,headd,jss,lt[e[i].u],lt[e[i].v]),cd[lt[e[i].u]]++,rd[lt[e[i].v]]++;for(int i=1;i<=lts;++i)if(rd[i]==0)q.push(i),f[i]=ltn[i],ff[i]=1;dfs();for(int i=1;i<=lts;++i){if(f[i]==maxd)maxf=(maxf+ff[i])%x;}printf("%d\n%d\n",maxd,maxf);return 0;
}

NC50403 嗅探器

题目:

• 某军搞信息对抗实战演习,红军成功地侵入了蓝军的内部网络,蓝军共有两个信息中心,红军计划在某台中间服务器上安装一个嗅探器,从而能够侦听到两个信息中心互相交换的所有信息,但是蓝军的网络相当的庞大,数据包从一个信息中心传到另一个信息中心可以不止有一条通路。现在需要你尽快地解决这个问题,应该把嗅探器安装在哪个中间服务器上才能保
证所有的数据包都能被捕获?
输出编号。如果有多个解输出编号最小的一个,如果找不到任何解,输出No solution。

题解:

• 肯定是个割点,但是割点还不够
• 起点到终点不在同一个点双连通分量里
• 起点到终点的路径要经过它,且他是必经之路的第一个点——搜索
在这里插入图片描述
详细讲讲为什么只求割点不行?如果题目给的a,b在一个连通块里,比如图中的2和5,我们求得1为割点,即便将1去掉,2和5依旧相连,所以我们不仅要求出割点,还要验证这个割点能否将a和b隔开
现在我们从a开始tarjan
如果v是u的儿子,当dfn[u]<=low[v]时说明u是割点
删掉u后,u和v必将隔开,如果b在v的一侧,而a不再v的一侧,这样u不就将a和b隔开了吗?
b在v的一侧说明:dfn[b]>=dfn[v]
a在v的另一侧说明:dfn[a]<dfn[v]
如果a在v的一侧,b不在也是同理

代码:

#include<bits/stdc++.h>
#include<vector>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=5e5+9;
vector<int>edge[maxn];
int a,b;
int low[maxn],dfn[maxn];
int cnt=0;
int ans=1e9;
bool check(int x)
{if(dfn[x]<=dfn[a]&&dfn[x]>dfn[b])return 1;if(dfn[x]<=dfn[b]&&dfn[x]>dfn[a])return 1;return 0;
}
void tarjan(int x,int fa)
{low[x]=dfn[x]=++cnt;for(int i=0;i<edge[x].size();i++){int v=edge[x][i];if(!dfn[v]){tarjan(v,x);low[x]=min(low[v],low[x]);if(low[v]>=dfn[x]&&x!=a&&x!=b&&check(v)){ans=min(ans,x);}}else if(v!=fa)low[x]=min(low[x],dfn[v]);}
}
int main()
{int n;cin>>n;int x,y;while(cin>>x>>y){if(x==0&&y==0)break;edge[x].push_back(y);edge[y].push_back(x);}cin>>a>>b;tarjan(a,a);if(ans==1e9)cout<<"No solution";else cout<<ans;
}

NC51269 Network of Schools

题目:

给你一张有向图,问最少要加几条边才能使得图上的点都属于同一个强连通分量

题解:

在这里插入图片描述
加边变成强连通分量
在这里插入图片描述

缩点之后,入度为0的点和出度为0的点两两连边,多随便一连——答案就是max(入度为0的点数,出度为0的点数)
在这里插入图片描述
处理后:
在这里插入图片描述

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=1e6+9;
vector<int>edge[maxn];
int low[maxn],dfn[maxn];
int vis[maxn];
int cnt=0;
stack<int>s;
int num1,num2;
int block; 
int color[maxn];
int in[maxn],out[maxn];
void tarjan(int u)
{low[u]=dfn[u]=++cnt;vis[u]=1;s.push(u);for(int i=0;i<edge[u].size();i++){int v=edge[u][i];if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(vis[v])low[u]=min(low[u],dfn[v]);}int x;if(dfn[u]==low[u]){block++;do{x=s.top();s.pop();vis[x]=0;color[x]=block;}while(x!=u);} 
}
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){int x;while(cin>>x){if(x==0)break;edge[i].push_back(x);}}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i);}for(int u=1;u<=n;u++){for(int i=0;i<edge[u].size();i++){int x=color[u];int y=color[edge[u][i]];if(x!=y){out[x]++;in[y]++;}}}for(int i=1;i<=block;i++){if(in[i]==0)num1++;if(out[i]==0)num2++;}if(block==1)cout<<"1"<<endl<<"0"<<endl;else printf("%d\n%d",num1,max(num1,num2));
}

NC106972 Cow Ski Area

题目:

• N*M的滑雪场,每个点都有他的高度,滑雪的时候只能向四周相邻的不高于当前点的高度的点滑,现在滑雪场准备修建若干个缆车线路,使得奶牛可以从任意一个点运动到滑雪场的每个点,问最少需要建多少条缆车线路。

题解:

本质还是有向图,通过加边使其强连通
• 相邻且高度一样的点建双向边,相邻但是高度不同的点建单向边,然后就是上一个题了——
tarjan缩点,统计入度和出度为零的点的个数。
• 有必要建图么?
• 相邻且高度一样的点在同一个连通块里——bfs就可以缩点,没必要tarjan

代码:

#include<map>
#include<set>
#include<list>
#include<stack>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>using namespace std;const int N  = 260000;
int dir[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
int mat[550][550];
int DFN[N];
int low[N];
int block[N];
int Stack[N];
int out[N];
int in[N];
bool instack[N];
int head[N];
int tot, sccnum, index, top, n, m;struct node
{int next;int to;
}edge[N << 2];void addedge(int from, int to)
{edge[tot].to = to;edge[tot].next = head[from];head[from] = tot++;
}void tarjan(int u)
{DFN[u] = low[u] = ++index;Stack[top++] = u;instack[u] = 1;for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (DFN[v] == 0){tarjan(v);if (low[u] > low[v]){low[u] = low[v];}}else if (instack[v]){if (low[u] > DFN[v]){low[u] = DFN[v];}}}if (DFN[u] == low[u]){sccnum++;do{top--;block[Stack[top]] = sccnum;instack[Stack[top]] = 0;}while (Stack[top] != u);}
}void solve(int ret)
{memset( instack, 0, sizeof(instack) );memset( DFN, 0, sizeof(DFN) );memset( low, 0, sizeof(low) );memset( in, 0, sizeof(in) );memset( out, 0, sizeof(out) );sccnum = index = top = 0;for (int i = 0; i < ret; i++){if (DFN[i] == 0){tarjan(i);}}if(sccnum == 1){printf("0\n");return ;}for (int i = 0; i < ret; i++){for (int j = head[i]; j != -1; j = edge[j].next){if (block[i] != block[edge[j].to]){out[block[i]]++;in[block[edge[j].to]]++;}}}int a = 0, b = 0;for (int i = 1; i <= sccnum; i++){if (in[i] == 0){a++;}if (out[i] == 0){b++;}}printf("%d\n", max(a, b));
}bool is_legal(int x, int y)
{if (x < 0 || x >= m || y < 0 || y >= n){return false;}return true;
}int main()
{while (~scanf("%d%d", &n, &m)){memset( head, -1, sizeof(head) );tot = 0;for (int i = 0; i < m; i++){for (int j = 0; j < n; j++){scanf("%d", &mat[i][j]);}}for (int i = 0; i < m; i++){for (int j = 0; j < n; j++){for (int k = 0; k < 4; k++){int ii = i + dir[k][0];int jj = j + dir[k][1];if ( !is_legal(ii, jj) ){continue;}if(mat[i][j] < mat[ii][jj]){continue;}else{addedge(i * n + j, ii * n + jj);}}}}solve(n * m);}return 0;
}

NC51307 Redundant Paths

题目:

• 给定无向连通图,求至少需要添加几条边使它变成一个边双连通图。
(添多少边可以消灭所有的桥)

题解:

先用边双连通缩点
• 缩点之后是一棵树
• 无根树的叶子(度数为1的点)都需要再添一条边,叶子节点两两连接
• 答案是是(叶子数+1)/2

在这里插入图片描述

代码:

这个题最坑的地方在于存在重边,我一直被卡。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
int n,m;
const int maxn=1e4+9;
vector<int>edge[maxn]; 
int low[maxn],dfn[maxn],vis[maxn];
int cnt=0;
int color[maxn],block=0;
stack<int>s;
int out[maxn];
int iff[maxn][maxn];
void tarjan(int u,int fa)
{low[u]=dfn[u]=++cnt;vis[u]=1;s.push(u);int b=0;for(int i=0;i<edge[u].size();i++){int v=edge[u][i];if(v==fa&&!b){b=1;continue;}if(!dfn[v]){tarjan(v,u);low[u]=min(low[u],low[v]);}else low[u]=min(low[u],dfn[v]);}int x;if(dfn[u]==low[u]){block++;do{x=s.top();s.pop();vis[x]=0;color[x]=block;}while(x!=u);} 
}
int lu[maxn],lv[maxn];
int main()
{
//	freopen("P2860_9.in","r",stdin);cin>>n>>m;for(int i=1;i<=m;i++){int u,v;cin>>u>>v;lu[i]=u;lv[i]=v;edge[u].push_back(v);edge[v].push_back(u);}for(int i=1;i<=n;i++){if(!dfn[i])tarjan(i,0);}int ans=0;for(int i=1;i<=m;i++){int u=lu[i];int v=lv[i];int x=color[u];int y=color[v];if(x!=y){out[y]++;out[x]++;}}for(int i=1;i<=block;i++){if(out[i]==1)ans++;}//ans++;cout<<(ans+1)/2;
}

NC20099 [HNOI2012]矿场搭建

题目:

• 煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。
• 于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。
• 请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数。

题解:

点双连通分量的性质:

  1. 任意两点间至少存在两条点不重复的路径等价于图中删去任意一个点都不会改变图的连通性,即BCC中无割点
  2. 若BCC间有公共点,则公共点为原图的割点
  3. 无向连通图中割点一定属于至少两个BCC,非割点只属于一个BCC

双连通分量重的割点是与其他双连通分量共享的点
• 先找割点和点双联通分量
• 对于一个点双联通分量
• 如果没有割点——2个通道——炸了一个还有一个,方案总数就是Cn2
• 一个割点——1个通道——建在不是割点的位置,如果它坍塌了也可以从隔壁的双连通分量里出去,方案总数就是n-1
• 两个割点——0个——不管哪个点塌了都可以从隔壁的双连通分量出去
本题关键在于dfs查找每一个连通块内割点数量

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
int head[505],dfn[505],low[505],vis[505],stack[505];
bool cut[505],in_stack[505];
int n,m,cnt,num,tot,deg,ans1,T,cases,root,top;
ll ans2;
struct node
{int from;int to;int next;
}e[1010];
inline void first()
{memset(head,0,sizeof(head));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(cut,0,sizeof(cut));memset(vis,0,sizeof(vis));top=cnt=tot=n=ans1=T=0; ans2=1;
}
inline void insert(int from,int to)
{e[++num].from=from;e[num].to=to;e[num].next=head[from];head[from]=num;
}
inline int read()
{int x=0,f=1; char c=getchar();while (c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while (c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x*f;
}
void Tarjan(int now,int father)//求割点 
{dfn[now]=low[now]=++tot;for(int i=head[now];i;i=e[i].next){int v=e[i].to;if(!dfn[v]){Tarjan(v,now);low[now]=min(low[now],low[v]);if(low[v]>=dfn[now]){if(now==root) deg++;else cut[now]=true;}}else if(v!=father) low[now]=min(low[now],dfn[v]);//不要跟求环混了 具体原理去网上找 }
}
void dfs(int x)//遍历每个连通块 
{vis[x]=T;//标记 if(cut[x]) return;cnt++;//数量 for(int i=head[x];i;i=e[i].next){int v=e[i].to;if(cut[v]&&vis[v]!=T) num++,vis[v]=T;//统计割点数目。 //如果是割点且标记不与遍历的的连通块相同就修改标记。 if(!vis[v])dfs(v);}
}
int main()
{m=read();while (m){first();for (int i=1;i<=m;i++){int u=read(),v=read();n=max(n,max(u,v));//这个地方要处理一下 insert(u,v); insert(v,u);}for (int i=1;i<=n;i++){if (!dfn[i]) Tarjan(root=i,0);if (deg>=2) cut[root]=1;//根节点的割点 deg=0;//不要忘记是多组数据 }for (int i=1;i<=n;i++)if (!vis[i]&&!cut[i])//不是割点 {T++; cnt=num=0;//T为连通块的标记 dfs(i);if (!num) ans1+=2,ans2*=cnt*(cnt-1)/2;//建两个 别忘记除以二 因为两个建立的出口没有差异 if (num==1) ans1++,ans2*=cnt;//建一个 }printf("Case %d: %d %lld\n",++cases,ans1,ans2);m=read();}return 0;
}

NC19981 [HAOI2010]软件安装

题目:

• 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
• 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。 • 我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

题解:

• 环套树?
• 一个环上的软件要么都装要么都不装
• 把环缩成点,然后建立一个虚根把所有连通块的根都连在虚根上,树型dp
• f[u][i]为在节点u的子树内,费用限制为i的条件下能取到的最大价值
f[u][i]=max(f[w][j]+f[x]][k]+V[u])
x是u的儿子
j+k+W[u] = i

NC51267 Knights of the Round Table

题目:

• 一些骑士,他们有些人之间有仇恨,现在要求选出一些骑士围成一圈,满足如下条件:
• 人数大于1 • 总人数为奇数
• 有仇恨的骑士不能挨着坐
• 问最少需要踢出去多少个骑士

题解:

• 能坐在一起的骑士都连边——
• 找一个尽量大的奇环
• 注意:有可能不是简单环
• 先求双连通分量
• 双连通分量里只有有一个环是奇环,那么整个环上每一点都可以在某个奇环里出现,即任意
两点之间都有两条长度和为奇数的路径
• 对每个双连通分量深搜染色即可

poj1515 NC106112 Street Directions

题目:

• 给你一张无向图,将尽量多的边变成定向的单向边,让所有的点都在一个强连通分量里面。
• 输出任意一种方案。

题解:

• 桥——不能变成单向边
• 其他的边——求边双连通分量的时候是树上的边就从上到下,是返祖边就从下到上。

NC51319 King’s Quest

题目:

N个男生和N个女生,告诉你每个男生喜欢的女生编号,然后给出一个初始匹配(这个初始匹配是一个完美匹配),求在保证匹配是完美匹配的基础上,输出每个男生可能会匹配的女生
在这里插入图片描述

题解:

参考题解:
让我们首先来考虑建图

如果王子u喜欢妹子v那我们可以从u向v连一条有向边

如果妹子v可以与王子u配对(即在配对表上),那我们可以从v向u连一条有向边

根据样例:

4
2 1 2
2 1 2
2 2 3
2 3 4
1 2 3 4

可以得到图
在这里插入图片描述
红的是王子,蓝的是妹子,绿的表示从王子到公主,黄的表示从妹子到王子

仔细观察我们发现了这张图的一些特别之处:
在这里插入图片描述
紫色部分为强连通分量
这表示在这个分量内的每个王子和这个分量内的每个妹子可以随便匹配
所以只需要枚举王子和他所在分量的妹子即可
tarjan,将同一强连通分量内的节点染色即可

相当于是利用完美匹配取找强连通分量
完美匹配建立反边,所给的关系建立正边,然后求强连通分量

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
struct edge {int v,nxt;
}ed[N];
stack<int> st;
int vis[N],head[N];
int low[N],dfn[N];
int cnt = 0,c2 = 0,c3 = 0;
int a[N];
vector<int> ans[N];
void add(int u,int v) {//链式前向星建边 cnt ++;ed[cnt].v = v;ed[cnt].nxt = head[u];head[u] = cnt;
}
void tarjan(int x) {//模板Tarjan算法 c2 ++;low[x] = dfn[x] = c2;st.push(x);//每个点进栈 vis[x] = 1;//表示这个点已进栈 for (int i = head[x];i;i = ed[i].nxt) {//遍历每条边 int v = ed[i].v;if (!dfn[v]) {//没有访问过 tarjan(v);low[x] = min(low[x],low[v]);}else if (vis[v]) {//这个点在栈里 low[x] = min(low[x],dfn[v]);}}if (low[x] == dfn[x]) {//强连通分量的根 c3 ++;int u;do{u=st.top() ;vis[u] = 0;//出栈,就去掉标记 a[u] = c3;//染色 st.pop();}while(x!=u);}
}inline void write(int x) {//快速输出 if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
int main() {int n;scanf("%d",&n);for (int i = 1;i <= n;i ++ ) {int t;scanf("%d",&t);//公主个数 for (int j = 1;j <= t;j ++ ) {int x;scanf("%d",&x);add(i,x + n);//王子向公主连边,注意公主编号从n+1开始 }}for (int i = 1;i <= n;i ++ ) {int x;scanf("%d",&x);add(x + n,i);//反向,公主向王子连边 }for (int i = 1;i <= n * 2;i ++ ) {//两倍 if (!dfn[i]) tarjan(i);}for (int i = 1;i <= n;i ++ ) {for (int j = head[i];j;j = ed[j].nxt) {int v = ed[j].v;if (a[i] == a[v]) {//找既是喜欢又同色的公主,加入答案ans[i].push_back(v);}}sort(ans[i].begin(),ans[i].end());//一定要排序!! }for (int i = 1;i <= n;i ++ ) {write(ans[i].size());//输出个数 putchar(' ');for (int j = 0;j < ans[i].size();j ++ ) {write(ans[i][j] - n);//编号最后要减n putchar(' ');}putchar('\n');}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318501.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Core WebAPI中使用JWT Bearer认证和授权

为什么是 JWT BearerASP.NET Core 在 Microsoft.AspNetCore.Authentication 下实现了一系列认证, 包含 Cookie, JwtBearer, OAuth, OpenIdConnect 等,Cookie 认证是一种比较常用本地认证方式, 它由浏览器自动保存并在发送请求时自动附加到请求头中, 更适用于 MVC 等纯网页系统的…

网络流专题(最大流与费用流)(一)

流量网络 • 想要将一些水从S运到T&#xff0c;必须经过一些水站&#xff0c;链接水站的是管道&#xff0c;每条管道都有它的最大能容纳的水量&#xff0c;求最多S到T能流多少流量。 基本概念 • 这是一个典型的网络流模型。我们先了解网络流的有关定义和概念。 • 若有向图G(…

eShopOnContainers 看微服务 ①:总体概览

一、简介eShopOnContainers是一个简化版的基于.NET Core和Docker等技术开发的面向微服务架构的参考应用。该参考应用是一个简化版的在线商城/电子商务微服务参考示例应用。其包含基于浏览器的Web应用、基于Xamarin的Android、IOS、Windows/UWP 移动应用&#xff0c;以及服务端应…

网络流专题(最大流与费用流)例题总结

文章目录NC 106056 poj1459 Power Network题目大意&#xff1a;题解&#xff1a;NC213817 [网络流24题]最小路径覆盖问题题目&#xff1a;题解&#xff1a;例2&#xff1a;NC213818 [网络流24题]魔术球问题题目&#xff1a;题解&#xff1a;方法2&#xff1a;NC 213820 [网络流…

周期长度和(KMP)

文章目录题目描述解析问题总结代码题目描述 解析 我们可以看到 如果A是B的周期 那么B一定可以写成&#xff1a; A1A2A1 的形式 注意到&#xff1a;A1就是KMP中的公共前后缀 要使A最大&#xff0c;要使A1最短 也就是求最短公共前后缀 这怎么求呢&#xff1f; 我们注意到&#x…

计算几何基础-1

文章目录基本概念点与向量的运算精度问题线段&#xff0c;射线和直线点积&#xff1a;夹角叉积向量的极角旋转一个向量求三角形面积直线交点点到直线距离点在直线上的投影判断两条线段是否相交点与直线的位置关系点是否在直线左侧点是否在直线上点是否在线段上点与多边形的位置…

.net core i上 K8S(四).netcore程序的pod管理,重启策略与健康检查

目录1.pod管理2.重启策略3.健康检查4.进入容器正文上一章我们已经通过yaml文件将.netcore程序跑起来了&#xff0c;但还有一下细节问题可以分享给大家。1.pod管理1.1创建podkubectl create -f netcore-pod.yaml我们创建一个netcore-pod.yaml文件&#xff0c;内容如下&#xff1…

洛谷P2680:运输计划(倍增、二分、树上差分)

传送门 文章目录题目描述解析问题代码题目描述 解析 求最大值的最小值 容易想到二分 然后。。。就没有然后了。。。 看了题解 学会了一个新技能&#xff1a;树上差分 &#xff08;其实学长之前好像讲过。。。&#xff09; 一般的&#xff0c;对于一条A到B的路径&#xff0c;如…

计算几何基础-2

文章目录直线&#xff1a;图形&#xff1a;求垂足求两圆交点直线与圆交点多边形问题判断一个点是否在任意多边形内部Pick定理凸包求点集的凸包水平法&#xff1a;增量法&#xff1a;半平面半平面交求半平面交直线&#xff1a; struct Line{point p,v;Line(){}Line(point _p.po…

eShopOnContainers 看微服务 ②:配置 启动

一、什么是dockerDocker 是一个开源项目&#xff0c;通过把应用程序打包为可移植的、自给自足的容器&#xff08;可以运行在云端或本地&#xff09;的方式&#xff0c;实现应用程序的自动化部署。使用 Docker 的时候&#xff0c;需要创建一个应用或服务&#xff0c;然后把它和它…

判断整除(opj)(动态规划)

解析 与取模结合的动归&#xff0c;正常做即可 问题 眼瞎&#xff01;&#xff01;&#xff01; 这个序列的每个数都必须用到&#xff01;&#xff01;&#xff01; if(f[i-1][j]) f[i][j]1;上面这行就是不对的&#xff01;&#xff01;&#xff01; 头疼 仔细审题 opj的题…

[USACO09FEB]Revamping Trails G

题意&#xff1a; 约翰一共有 N 个牧场.由 MM 条布满尘埃的小径连接。小径可以双向通行。每天早上约翰从牧场 1 出发到牧场 N 去给奶牛检查身体。 通过每条小径都需要消耗一定的时间。约翰打算升级其中 K 条小径&#xff0c;使之成为高速公路。在高速公路上的通行几乎是瞬间完…

NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成...

本篇内容属于非实用性&#xff08;拿来即用&#xff09;介绍&#xff0c;如对框架设计没兴趣的朋友&#xff0c;请略过。 快一个月没有写博文了&#xff0c;最近忙着两件事;一&#xff1a;阅读刘墉先生的《说话的魅力》&#xff0c;以一种微妙的&#xff0c;你我大家都会经常遇…

花店橱窗布置(洛谷P1854)(动态规划)

传送门 文章目录解析问题代码解析 一道很正常的动态规划 dp[i][j]表示到第j个花瓶放了第j朵花的dp最优值 注意&#xff1a;是严格使第i朵放在j瓶 找到最优解递归输出即可 问题 又是初始化的问题&#xff01;&#xff01;&#xff01; 一开始把dp赋值成负无穷时落掉了j0的一行…

P4009 汽车加油行驶问题

题目描述&#xff1a; 题解&#xff1a; 看了很多题解&#xff0c;无论什么解法都绕不开分层图 在本题中加满油的车每次可以移动K步&#xff0c;那么我们就可以建立一个K1层的分层图&#xff0c;表示汽车油量k的状态&#xff08;油量0…k&#xff09;&#xff0c;然后根据题目…

.net core i上 K8S(五).netcore程序的hostip模式

正文上一章讲了pod的管理&#xff0c;今天再分享一个pod的访问方式1.Pod的HostIP模式Pod的HostIP模式&#xff0c;可以通过宿主机访问pod内的服务&#xff0c;创建yaml文件如下apiVersion: v1 kind: Pod metadata: name: netcore-podlabels:app: netcorepod spec:containers: …

状态压缩:枚举子集(最优组队)(ybtoj)(动态规划)

解析 很裸的状压dp 但是直接暴力的话状态2n,枚举2n 乘在一起会T诶 怎么办呢&#xff1f; 使用下面这个循环&#xff0c;就可以保证只会枚举当前状态s的子集 for(int i(s-1)&s;i;i(i-1)&s){........ }证明 举举例子就挺明显了 为什么不重不漏呢&#xff1f; 首先i肯…

【活动(深圳)】告别2018之12.22 大湾区.NET Meet 大会 ,同时有网络直播

今年的 Connect(); 主题更加聚焦开发者工具生产力、开源&#xff0c;以及无服务器&#xff08;Serverless&#xff09;云服务。Visual Studio 2019 AI 智能加持的 IntelliCode、实时代码协作共享 Live Share&#xff0c;.NET Core 3.0的预览版本附带了大量更新&#xff0c;旨在…

最短路径(状压dp)(ybtoj)

解析 “bug总有de完的一天” 头疼 暴力写的话本题显然复杂度是假的 有一个很好的思路优化时间复杂度 先用dp[k][i]表示**从第k个关键点到任意i点的最短路 跑k遍 SPFA或迪杰斯特拉 即可 然后转移时可以只考虑关键点 使状态转移数大大降低 细节 头真疼 边界条件&#xff1a; …

P2403 [SDOI2010]所驼门王的宝藏(强连通分量)(拓扑排序)

文章目录题目描述解析代码洛谷传送门题目描述 解析 看题目要求很容易想到强连通分量缩点加拓扑dp 但是问题在于存图 第一感就是和暴力和每个点连边 但那样无论点数和边数都很爆炸 随后我们发现这个图非常稀疏 所以我们可以只连有宝藏的点 然而这样边数会被一行横门这样的数据…