您的位置:首页 > 其它

2015-2016 下半学期 第八周 训练

2016-05-07 17:19 387 查看
1、poj1144

题意:求割点数目。

思路:dfs

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;

int times,root;
int visit[105],flag[105];
int low[105],dfn[105];
vector <int> map[105];
int min(int a,int b)
{   return a<b?a:b;  }
void dfs(int v)
{
int i,w,cnum=0;//cnum 表示孩子的个数
times++;
visit[v]=1;
dfn[v]=low[v]=times;  //记录时间戳
for(i=0;i<map[v].size();i++)
{
w=map[v][i];
if(!visit[w])//没有被访问过,则w是v的孩子结点
{
cnum++;
dfs(w);
low[v]=min(low[w],low[v]);
if(v==root&&cnum==2)
flag[v]=1;//如果v是根,且有2个以上的孩子,则是割点
if(v!=root&&low[w]>=dfn[v])
flag[v]=1;//不为根若low[w]>=dfn[v],则是割点
}
else if(v!=w)
{//w已经访问过了,说明从v到w有一条回边,w是v的祖先
low[v]=min(low[v],dfn[w]);
}
}
}

int main()
{
int n;
while(scanf("%d",&n)==1&&n)
{
int a,b;
int i,ans=0;
char c;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(visit,0,sizeof(visit));
memset(flag,0,sizeof(flag));
for(i=0;i<=n;i++)map[i].clear();
while(scanf("%d",&a)==1&&a)
{
while((c=getchar())!='\n')
{
scanf("%d",&b);
map[a].push_back(b);
map[b].push_back(a);
}
}
times=0;root=1;
dfs(root);
for(i=1;i<=n;i++)
if(flag[i])ans++;
printf("%d\n",ans);
}
return 0;
}


2、hdu4635

题意:给n个点的有向图,问最多加多少边图仍然是非强连通图。

思路:

最后形成的图,一定是分为A部分和B部分,并且只有A向B的边没有B向A的边,为了使边数最多,AB必须都是完全图。

假设A有x个点,B有y个点,x+y=n 总边数 f=x*y+x*(x-1)+y*(y-1)=n^2-n-x*y。

那么x和y的差值越大 f越大,所以我们先将图缩点,之后找出度或入度为0的包含节点数最多的那给点作为B,剩下的点合起来作为A。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long  long
#define db double
#define EPS 1e-8
#define inf 1e9

using namespace std;

const int N = 100005;
struct EDG{
int to,nxt;
}e
;
int eid,head
;
int low
,dfn
,vis
,num
,id
,deep,stack1
,tn,top;
int in
,out
;

void init(){
eid=tn=top=deep=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(num,0,sizeof(num));
}
void add(int u,int v){
e[eid].to=v;
e[eid].nxt=head[u];
head[u]=eid++;
}
void tarjan(int u){
stack1[++top]=u;
vis[u]=1;
deep++;
low[u]=dfn[u]=deep;
for (int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if (vis[v]==0){
vis[v]=1;
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if (vis[v]==1)
low[u]=min(low[u],dfn[v]);
}
if (low[u]==dfn[u]){
tn++;
do{
vis[stack1[top]]=2;
num[tn]++;
id[stack1[top]]=tn;
}while (stack1[top--]!=u);
}
}
__int64 solve(int n,int m){
__int64 ans=n*(n-1)-m;
int minnum=N;
for (int i=1;i<=n;i++)
if (vis[i]==0) tarjan(i);
if (tn==1) return -1;
for (int u=1;u<=n;u++)
for (int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].to;
if (id[u]!=id[v])
in[id[v]]++,out[id[u]]++;
}
for (int i=1;i<=tn;i++)
if (in[i]==0 || out[i]==0)
minnum=min(minnum,num[i]);
ans-=minnum*(n-minnum);
return ans;
}
int main(){
int T,n,m,c=0,a,b;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
init();
for (int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
add(a,b);
}
printf("Case %d: %I64d\n",++c,solve(n,m));
}
return 0;
}


3、codeforces 22c

题意:构造一个以点v为割点的图。

思路:

找一个顶点只和v连,剩下的边在其余n-2个点上连,注意无法成立的条件。

代码:

#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;

const int SZ = 100002;
int n, m, v;
bool vis[SZ];

int main()
{
while(scanf("%d %d %d", &n, &m, &v) != EOF)
{
if(m < n - 1 || m > ((n - 2) * (n - 3)) / 2 + n - 1)
puts("-1");
else if(n < 3)
{
puts("1 2");
}
else
{
int u = v - 1;
if(v == 1) u = 2;
for(int i = 1; i <= n; i++)
{
if(i != v)
printf("%d %d\n", i, v);
}
m -= (n - 1);
for(int i = 1; i <= n && m; i++)
{
if(i == v || i == u) continue;
for(int j = i + 1; j <= n && m; j++)
{
if(j == v || j == u) continue;
printf("%d %d\n", i , j);
m--;
}
}
}
}
return 0;
}


4、codeforces 22e

题意:加最少的边使原有向图边成强连通图

思路:缩点后将这些点首尾相连。

代码:

#include <cstdio>
#include <vector>

using namespace std;

#define N 100001

int in
, col
;
vector<int> adj
, beg, end;

int dfs(int p)///找环
{
col[p] = 1;
int v = adj[p][0];
if (!col[v]) return col[p] = dfs(v);
else return col[p] = p;
}

int main()
{
int n, a;
while(~scanf("%d", &n))
{
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a);
in[a]++;
adj[i].push_back(a);
}

int k = 0;
for (int i = 1; i <= n; ++i)
{
if (!in[i])
{
beg.push_back(i);
end.push_back(dfs(i));
++k;
}
}
int t = k;
for (int i = 1; i <= n; ++i)
{
if (!col[i])
{
beg.push_back(i);
end.push_back(dfs(i));
++k;
}
}
if (k == 1 && t == 0) k = 0;
printf("%d\n", k);
for (int i = 0; i < k; ++i)
printf("%d %d\n", end[i], beg[(i+1)%k]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: