hdu 6041 I Curse Myself
题目:
点这里OvO http://acm.hdu.edu.cn/showproblem.php?pid=6041
2017 Multi-University Training Contest - Team 1 - 1009
题解:
1.由于每条边只在一个环中,每个环必然要拿掉一条边,而这些边都是不重复的,那么最小生成树就对应的是通过求每个环中拿掉一条边,总和最大的组合对应的剩下的树(第k小生成树对应第k大组合剩下的树)。xjbdfs搜一下环,把每个环中的点放到一个集合中。
2.然后对集合排序,xjb利用优先队列 ( 要注意优先队列中的元素的数量要保持和新集合的元素个数相同,以降低时间复杂度 ) 求最大的k(如果总数没k个那就不是k个)个组合(每个集合中取一个元素的组合)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cmath> 6 #include <vector> 7 #include <queue> 8 9 using namespace std; 10 11 typedef long long ll; 12 13 const int N=1e4+55; 14 const int M=2e3+44; 15 const ll mod=(ll)pow(2,32); 16 17 struct node{ 18 int u,v,d; 19 int next; 20 }edge[2*N]; 21 22 struct NODE 23 { 24 int v,now; //value is (v), now add with (now) 25 friend bool operator<(NODE x,NODE y) 26 { 27 return x.v < y.v; 28 } 29 };//small to big 30 31 priority_queue<NODE> Q; 32 int num; 33 int head[N]; 34 int n,m,k; 35 ll ans; 36 int snum; 37 int stk[N],lstk; 38 bool instk[M]; 39 vector<int> s[N]; 40 int val[M][M]; 41 vector<int> f,tmpf; 42 ll sum_of_edge; 43 ll du[M]; 44 45 bool cmp(int a,int b) 46 { 47 return a>b; 48 } 49 50 void addedge(int u,int v,int d) 51 { 52 edge[num].u=u; 53 edge[num].v=v; 54 edge[num].d=d; 55 edge[num].next=head[u]; 56 head[u]=num++; 57 } 58 59 void init() 60 { 61 num=0; //记得初始化 62 memset (head,-1,sizeof(head)); 63 memset(du,0,sizeof(du)); 64 snum=0; 65 lstk=0; 66 memset(instk,0,(n+4)*sizeof(bool)); 67 for(int i=1;i<=n;i++) 68 s[i].clear(); 69 ans=0; 70 sum_of_edge=0; 71 } 72 73 void dfs(int rt,int fa) 74 { 75 int v; 76 if(instk[rt]) 77 { 78 snum++; 79 int sav=rt; 80 int sav_lstk=lstk; 81 while(stk[lstk]!=rt) 82 { 83 s[snum].push_back(val[sav][stk[lstk]]); 84 sav=stk[lstk--]; 85 } 86 s[snum].push_back(val[sav][stk[lstk]]); 87 lstk=sav_lstk; 88 return ; 89 } 90 instk[rt]=1; 91 stk[++lstk]=rt; 92 for(int i=head[rt];i!=-1;i=edge[i].next) 93 { 94 v=edge[i].v; 95 if(v==fa || du[v]==0) continue; 96 du[rt]--; du[v]--; 97 dfs(v,rt); 98 } 99 instk[rt]=0; 100 lstk--; 101 } 102 103 void merge() 104 { 105 NODE q; 106 int i,j,cnt; 107 f.clear(); 108 if(snum==0) 109 { 110 f.push_back(0); 111 return ; 112 } 113 for(int i=0;i<s[1].size();i++) 114 f.push_back(s[1][i]); 115 for(int i=2;i<=snum;i++) 116 { 117 cnt=f.size()*s[i].size(); 118 if(cnt>k) cnt=k; 119 while(!Q.empty()) 120 Q.pop(); 121 for(j=0;j<s[i].size();j++) 122 { 123 q.v=s[i][j]+f[0]; 124 q.now=0; 125 Q.push(q); 126 } 127 tmpf.clear(); 128 while(cnt--) 129 { 130 q=Q.top(); 131 Q.pop(); 132 tmpf.push_back(q.v); 133 if(q.now!=f.size()-1) 134 { 135 q.v-=f[q.now]; 136 q.now++; 137 q.v+=f[q.now]; 138 Q.push(q); 139 } 140 } 141 swap(f,tmpf); 142 } 143 // cout<<"check merge\n"; 144 // for(int i=0;i<f.size();i++) 145 // printf("%d ",f[i]); 146 // printf("\n"); 147 // printf("end of check of merge\n"); 148 } 149 150 void solve() 151 { 152 dfs(1,-1); 153 for(int i=1;i<=snum;i++) 154 sort(s[i].begin(),s[i].end(),cmp); 155 // printf("check s\n"); 156 // for(int i=1;i<=snum;i++) 157 // { 158 // for(int j=0;j<s[i].size();j++) 159 // printf("%d",s[i][j]); 160 // printf("\n"); 161 // } 162 // printf("end of check of s\n"); 163 merge(); 164 } 165 166 int main() 167 { 168 int cas=0,a,b,c; 169 while(scanf("%d%d",&n,&m)!=EOF) 170 { 171 init(); 172 for(int i=1;i<=m;i++) 173 { 174 scanf("%d%d%d",&a,&b,&c); 175 addedge(a,b,c); 176 addedge(b,a,c); 177 du[a]++; du[b]++; 178 val[a][b]=val[b][a]=c; 179 sum_of_edge+=c; 180 } 181 scanf("%d",&k); 182 solve(); 183 for(int i=0;i<f.size();i++) 184 ans=(ans+1ll*(i+1)*(sum_of_edge-f[i])%mod)%mod; 185 printf("Case #%d: %lld\n",++cas,ans%mod); 186 } 187 return 0; 188 }