图论杂题

1.https://www.luogu.org/problemnew/show/CF827A

/*首先考虑暴力,那就是每次for,显然时间无法承受
如果我们知道开头最远能到哪,就可以节省时间了,那我们
将以i开头向右最远能到的点记作fa[i]也就是关键点*/
#include<bits/stdc++.h>
using namespace std;
const int N=4e6+1;
int n,x,num,pos,maxn,fa[N];
char ans[N],s[N];
int getfa(int x){return fa[x]==x? x:fa[x]=getfa(fa[x]);}
int main()
{
	//freopen("a.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=4000000;i++)fa[i]=i;
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		int len=strlen(s+1);
		scanf("%d",&num);
		for(int j=1;j<=num;j++){
			scanf("%d",&x);
			maxn=max(maxn,x+len-1);
			pos=x;
			while(1){
				pos=getfa(pos);
				if(pos>x+len-1)break;//最右端超过本身长度显然要break 
				ans[pos]=s[pos-x+1];//更新当前点信息 
				fa[pos]=fa[getfa(pos+1)];//将pos合并到pos+1 
				pos=fa[pos];//找到下一个没有被覆盖的点 
			}
		}
	}
	for(int i=1;i<=maxn;i++){
		if(ans[i]=='\0')putchar('a');
		else putchar(ans[i]);
	}
	return 0;
}

2.http://codeforces.com/contest/1063

/*
我怎么连bfs都不会写了啊 
刚开始还以为直接bfs就行了,没想到我还是too youung 
由于左右步数有限制,所以第一次bfs的不一定是最优解
那么发现同时记录向左和向右的最优解在更新。。。不太好写啊
看了题解后:
我们可以发现对于一个点我们只关心走到它向左最少走多少步即可
因为向左步数越少,向右步数就越少,然后就可以做了
就是0/1bfs 双端队列即可(第一次写双端队列)QAQ 
0/1bfs逐层扩展保证最先搜到的就是最优解 
附上失败代码: 
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=2100;
struct node{int x,y;}q[5000000];
int n,m,r,c,limitx,limity,tot=1,head=1,tail=0,v[N][N],lc[N][N],rc[N][N];
char a[N][N];
void bfs(int lx,int ly){
    q[++tail].x=lx,q[tail].y=ly;
    v[lx][ly]=1;
    while(head<=tail){
        int x=q[head].x,y=q[head].y;head++;
        int xx,yy;
        {
            xx=x-1,yy=y;
            if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
                lc[xx][yy]=lc[x][y];
                rc[xx][yy]=rc[x][y];
                q[++tail].x=xx;
                q[tail].y=yy;
                v[xx][yy]=1;
                tot++;
            }
            xx=x+1,yy=y;
            if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
                lc[xx][yy]=lc[x][y];
                rc[xx][yy]=rc[x][y];
                q[++tail].x=xx;
                q[tail].y=yy;
                v[xx][yy]=1;
                tot++;
            }
        }
        {
            if(lc[x][y]<limitx){
                xx=x,yy=y-1;
                if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
                    lc[xx][yy]=lc[x][y]+1;
                    rc[xx][yy]=rc[x][y];
                    q[++tail].x=xx;
                    q[tail].y=yy;
                    v[xx][yy]=1;
                    tot++;
                }
            }
            if(rc[x][y]<limity){
                xx=x,yy=y+1;
                if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
                    lc[xx][yy]=lc[x][y];
                    rc[xx][yy]=rc[x][y]+1;
                    q[++tail].x=xx;
                    q[tail].y=yy;
                    v[xx][yy]=1;
                    tot++;
                }
            }
        }
    }
}
int main()
{
    freopen("a.in","r",stdin);
    scanf("%d%d%d%d%d%d",&n,&m,&r,&c,&limitx,&limity);
    rep(i,1,n)rep(j,1,m)cin>>a[i][j];
    bfs(r,c);
    cout<<rc[6][3];
    //out<<tot;
    return 0;
}*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=3000;
struct node{int x,y;node(int _x=0,int _y=0){x=_x;y=_y;}};
int n,m,r,c,limitx,limity,tot=0,d[N][N],v[N][N];
int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};
char a[N][N];
deque<node> q;
void bfs(int sx,int sy){
	memset(d,-1,sizeof(d));
	q.push_front(node(sx,sy));
	d[sx][sy]=0;
	while(q.size()){
		node t=q.front();q.pop_front();
		rep(i,0,3){
			int x=t.x+dx[i],y=t.y+dy[i];
			if(x<1||x>n||y<1||y>m||a[x][y]=='*'||(d[x][y]!=-1&&d[x][y]<=d[t.x][t.y]+(i==3)))continue;
			d[x][y]=d[t.x][t.y]+(i==3);
			if(i==3)q.push_back(node(x,y));
			else q.push_front(node(x,y));
		}
	}
}
int main()
{
	//freopen("a.in","r",stdin);
	scanf("%d%d%d%d%d%d",&n,&m,&r,&c,&limitx,&limity);
	rep(i,1,n)rep(j,1,m)cin>>a[i][j];
	bfs(r,c);
	rep(i,1,n){
		rep(j,1,m){
			if(d[i][j]==-1)continue;
			int a=d[i][j],b=j-c+a;
			if(a<=limitx&&b<=limity)tot++;
		}
	}
	cout<<tot;
	return 0;
}

3.https://www.luogu.org/problemnew/show/CF1060E

/*
将题意化简后就变成了求∑∑(dis(i,j)+1)/2;
感觉思想江化了啊,看题解,后来才想明白
∑∑dis(i,j)/2其实是很好算的吧
如果dis(i,j)是偶数,那么答案就是 (1/2)* ∑∑dis(i,j)
但是有距离是奇数的边,那我们可以发现答案就是 (1/2)* (∑∑dis(i,j)+奇数边个数)
证明不是很会,还涉及太多分类讨论 就当结论记住吧 
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6;
struct node{int y,n;}e[N];
int deep[N],size[N],lin[N],len=0,num=0,n,x,y;
long long ans=0;
void read(int x,int y){e[++len].y=y,e[len].n=lin[x],lin[x]=len;}
void dfs(int x,int fa){
	size[x]=1;
	for(int i=lin[x];i;i=e[i].n){
		int y=e[i].y;
		if(y==fa)continue;
		deep[y]=deep[x]+1;
		dfs(y,x);
		size[x]+=size[y];
	}
}
int main()
{
	scanf("%d",&n);
	rep(i,1,n-1){scanf("%d%d",&x,&y);read(x,y),read(y,x);}
	dfs(1,1);
	rep(i,1,n){
		ans+=1LL*size[i]*(n-size[i]);
		if(deep[i]%2)num++;
	}
	ans+=1LL*num*(n-num);
	cout<<ans/2;
	return 0;
}

4.http://codeforces.com/problemset/problem/999/E

/*
tarjan缩点,形成一个DAG,那么就找入度为0的点,如果有入度为0的点
且这个点不是起点,那么就需要向这个点连一条边,否则就不用,好像
如果入度不为0,那么不管怎样都能到达这个点,(感性理解一下是对的QAQ) 
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6;
stack<int> S;
struct node{int x,y,n;}e[N];
int lin[N],dfn[N],low[N],inv[N],du[N],c[N],scc=0,tot=0,ans=0,len=0,x,y,n,m,s;
void read(int x,int y)
{e[++len].y=y,e[len].x=x,e[len].n=lin[x],lin[x]=len;}
void tarjan(int x){
	dfn[x]=low[x]=++tot;
	S.push(x); inv[x]=1;
	for(int i=lin[x];i;i=e[i].n){
		int y=e[i].y;
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}else if(inv[y]) low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x]){
		int now=0;scc++;
		while(now!=x){
			now=S.top();S.pop();
			inv[now]=0;
			c[now]=scc;
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&s);
	rep(i,1,m){scanf("%d%d",&x,&y);read(x,y);}
	rep(i,1,n)if(!dfn[i])tarjan(i);
	rep(i,1,len){
		x=e[i].x,y=e[i].y;
		if(c[x]==c[y])continue;
		du[c[y]]++;
	}
	rep(i,1,scc)if(du[i]==0&&c[s]!=i)ans++;
	cout<<ans;
	return 0;
}

5.http://codeforces.com/problemset/problem/1003/E

/*
可以发现度数的限制其实容易解决,那么难点就在直径上
我想的是先解决度数再去调整直径,显然很不可做
看了题解才知道先构造直径,再去在直径上挂点
link(i,i+1)(i=1 to d )
显然一个点上挂的深度最多为min(i-1,d-i+1)
dfs挂点就行了 
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6;
struct node{int x,y;}e[N];
int n,d,k,now=0,len=0;
void read(int x,int y){e[++len].x=x,e[len].y=y;}
void dfs(int x,int deep,int maxn){
	if(deep==maxn)return;
	for(int i=1;i<=k-1-(deep==0)&&now<n;i++){
		read(x,++now);
		dfs(now,deep+1,maxn);
	}
}
int main()
{
	scanf("%d%d%d",&n,&d,&k);
	rep(i,1,d)read(i,i+1);
	now=d+1;
	rep(i,2,d)dfs(i,0,min(i-1,d-i+1));
	if(now<n||k<2&&d>1||n<=d){cout<<"NO\n";return 0;}
	cout<<"YES\n";
	rep(i,1,len)printf("%d %d\n",e[i].x,e[i].y);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值