其实是一道裸题,如果没学过最短路树的话会比较难做,要想很久想到关键性质才能做出来。
最短路树顾名思义,就是从一个图中生成出来一棵树,使得每个顶点到root的距离是单源最短路。如果有这样的树的话,那可见这样的树是符合题意的。
怎么生成这样的树呢?关键在于记录前驱father,一个距离root最短路是6的点必定从一个距离root最短路是5的点到达(这两个点之间一定会有一条边)。所以我们对于所有顶点 2-n,每个顶点u我们找dis[u] = dis[v]+1的情况,这样的话v就是u的前驱。若v,u之间有一条边,那u到root的最短路就解决了【因为如果v到root的最短路不变,那u也不变】,原问题就变成了子问题,这就是这么建树 正确性的理解。
所有合法前驱记录完后,我们dfs下枚举所有前驱就可以了。【最多能生成father[2].size() * father[3].size() * ... * father[n].size()个合法答案】
1 #include<iostream> 2 #include<vector> 3 #include<map> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 8 char comp[200005]; 9 vector< pair<int,int> > edge[200005]; 10 vector<int> father[200005]; 11 vector<string> ans; 12 int dis[200005],n,k; 13 queue< pair<int,int> > q; 14 15 void dfs(int u){ 16 if( ans.size()>=k ) return; 17 if(u==n+1) { ans.push_back(comp+1); return;}//建完了 18 for(int i=0;i<father[u].size();i++){ 19 comp[ father[u][i] ] = ‘1‘;//从众多前驱中挑一个 20 dfs(u+1); 21 comp[ father[u][i] ] = ‘0‘; 22 } 23 } 24 25 int main(){ 26 int m; cin>>n>>m>>k; 27 for(int i=1;i<=m;i++){ 28 int u,v; scanf("%d %d",&u,&v); 29 edge[u].push_back( make_pair(v,i) ); 30 edge[v].push_back( make_pair(u,i) );//建两条边 31 } 32 33 34 memset(dis,-1,sizeof(dis)); 35 for (int i = 1; i <= m; i++) comp[i] = ‘0‘; 36 //维护出dis数组 37 q.push( make_pair(1,0) ); dis[1]=0; 38 while(!q.empty()){ 39 pair<int,int> pa = q.front(); q.pop(); 40 int u=pa.first,d=pa.second; 41 for(int i=0;i<edge[u].size();i++){ 42 int v=edge[u][i].first; 43 if( dis[v]==-1 ) { 44 dis[v]=d+1; 45 q.push( make_pair(v,d+1) ); 46 } 47 } 48 } 49 //找最短路数里每个顶点的前驱 50 for(int i=2;i<=n;i++){ 51 for(int j=0;j<edge[i].size();j++){ 52 if( dis[i]==dis[ edge[i][j].first ]+1 ) father[i].push_back( edge[i][j].second ); 53 } 54 } 55 56 dfs(2);//从2开始建树 57 if(ans.size()>=k){ 58 cout<<k<<endl; 59 for(int i=0;i<k;i++) cout<<ans[i]<<endl; 60 } 61 else{ 62 cout<<ans.size()<<endl; 63 for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl; 64 } 65 66 67 return 0; 68 }
原文地址:https://www.cnblogs.com/ZhenghangHu/p/9315157.html
时间: 2024-10-09 17:25:03