CF1005F Berland and the Shortest Paths

在这里插入图片描述

在这里插入图片描述

analysis

是的,这道题是用最短路树(图)做的

要证明(理解)最短路树(图)就是本题的合法答案的话,有下面两种方式

  • 假设我们现在有随机的一个方案(n-1条边),那么对于每一个点i,如果它的 d i d_i di在用方案里n-1条边的时候不是最小值的话说明还可以更改路径使得 d i d_i di更小,而最短路树(图)上面的每个点的 d i d_i di都是最小的,因此总和 ∑ d i \sum d_i di也是最小的
  • 假设最短路树所给出的方案不是最小的,那么假设有另一个树A使得A给出的方案最小,那么必然有某一点i使得A中的 d i d_i di小于最短路树中的 d i d_i di这与最短路树的定义矛盾

于是先求出最短路树(其实本题中求出的是最短路图(一个DAG),因为最短路树在本题中是不唯一的)

而本题要求输出的是方案总数和具体方案,实质上就是在最短路图中求选择n-1条边的方案数和具体方案,那么根据乘法原理,方案数= ∏ u ∈ [ 1 , n ] f a [ u ] . s i z e ( ) \prod_{u\in[1,n]} fa[u].size() u[1,n]fa[u].size()(fa[u].size(),u的可选父节点的个数),输出方案数也就是枚举每一个点的可选边然后打标记罢了

code

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long
template<typename T>void read(T &x){
	x=0;char r=getchar();T neg=1;
	while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
	while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
	x*=neg;
}
int n,m,k;
const int maxn=2e5+10;
const int maxm=2e5+10;
const int maxk=1e5+10;
struct node{
	int e;
	int w;
	int id;
	int nxt;
}edge[maxm<<1];
int head[maxn];
int cnt=0;
inline void addl(int u,int v,int id){
	edge[cnt].e=v;
	edge[cnt].w=1;
	edge[cnt].id=id;
	edge[cnt].nxt=head[u];
	head[u]=cnt++;
}
struct point{
	int pos;
	int w;
	point():pos(0),w(0){}
	point(int pos,int w):pos(pos),w(w){}
	friend bool operator<(point a,point b){
		return a.w>b.w;
	}
};
priority_queue<point>q;
int dis[maxn];
int f[maxn];
vector<int>vec[maxn];
inline void dijkstra(int S){
	clean(dis,0x3f);
	dis[S]=0;
	q.push(point(S,0));
	while(q.empty()==false){
		int f=q.top().pos;
		q.pop();
		for(int i=head[f];i!=-1;i=edge[i].nxt){
			int v=edge[i].e;
			if(dis[v]>dis[f]+edge[i].w){
				vec[v].push_back(edge[i].id);
				dis[v]=dis[f]+edge[i].w;
				q.push(point(v,dis[v]));
			}
			else if(dis[v]==dis[f]+edge[i].w)
				vec[v].push_back(edge[i].id);
		}
	}
}
int usd[maxm];
int tot=1;
int num=0;
void dfs(int dep){
	if(dep==n+1){
        for(int i=1;i<=m;i++){
            printf("%d",usd[i]);
        }
        printf("\n");
        num++;
        if(num==tot){
            exit(0);
        }
        return;
    }
    for(int i=0;i<vec[dep].size();i++){
        usd[vec[dep][i]]=1;
        dfs(dep+1);
        usd[vec[dep][i]]=0;
    }
}
int main(){
	clean(head,-1);
	clean(usd,0);
	read(n);
	read(m);
	read(k);
	loop(i,1,m){
		int ai,bi;
		read(ai);
		read(bi);
		addl(ai,bi,i);
		addl(bi,ai,i);
	}
	dijkstra(1);
	loop(i,2,n){
		tot*=vec[i].size();
		if(tot>=k){
			tot=k;
			break;
		}
	}
	printf("%d\n",tot);
	dfs(2);
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值