codeforces D. Edge Deletion+最短路樹(優先佇列優化)
阿新 • • 發佈:2018-12-22
題目連結:http://codeforces.com/contest/1076/problem/D
題目大意:
在一個n個點m條邊的無向圖中起點為1,設初始到達第i個點的最短距離為d[i],
現在要求在圖上刪邊,使剩下的邊等於k條,並讓儘量多的點d[i]與之前相等
最短路:
可以看出來,這就是一棵樹,因為是最短路,所以稱為最短路樹。
保留k條邊。在數上bfs或者dfs訪問k條邊記錄下來就可以。
建樹只要記錄每個節點由哪個節點,哪條邊,鬆弛的就可以了。
dfs保留編號3, 2或者編號5, 3。
bfs保留編號編號3, 1。
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxm 600005 #define maxn 300005 #define inf 0x3f3f3f3f3f3f3f3f struct P { int to; ll cost; bool operator < (const P & a) const { return cost>a.cost; } }; struct node { int to; //終點 ll val; //權力 int nxt;//同個起點的下一條邊(-1)終止 int id; //邊的編號 int s; }edge[maxm]; //head[i]記錄了以i為起點的最後一條邊的下標,並且可以通過id找到i為起點d的下一條邊 //這樣就遍歷了以i為起點所有邊 int head[maxn],tot=0;//head和tot記得重置,head重置為-1 int n,m;//點數,邊數,不要再main裡面重新定義 bool vis[maxn];//每次在dij裡面初始化為0 ll dis[maxn];//根據題意初始化為inf可能int可能longlong void addedge(int x,int y,ll val,int id) { edge[tot].to=y; edge[tot].val=val; edge[tot].nxt=head[x]; edge[tot].id=id; head[x]=tot++; } int pre[maxn];//記錄每個點的點前驅 int prem[maxn];//每個點的邊前驅 //int vv[maxn]; void Dijkstra(int s) { memset(vis,0,sizeof(vis)); fill(dis,dis+n+2,inf); dis[s]=0; priority_queue<P>q; q.push(P{s,0}); while(!q.empty()) { P p1=q.top();q.pop(); int u=p1.to; if(dis[u] < p1.cost)continue; //如果目前的值已經比進堆時小了,就沒必要再過一遍了,有的題會卡這個時間 vis[u]=1; for(int i=head[u];i+1;i=edge[i].nxt) { int v=edge[i].to; if(vis[v])continue;//判斷節點v是否加入最短路樹中 if(dis[v]>dis[u]+edge[i].val) { pre[v]=u; //記錄每個點的點前驅 prem[v]=edge[i].id;//記錄每個點的邊前驅 dis[v]=dis[u]+edge[i].val; q.push(P{v,dis[v]}); } } } } vector<pair <int, int> > G[maxn]; vector<int> ans; int ind[maxn]; int cc,k; void dfs(int st)//對節點深搜 { if(cc==k) return ; for(int i=0;i<G[st].size();i++) { cc++; ans.push_back(G[st][i].second); if(cc==k) return; dfs(G[st][i].first); if(cc==k) return ; } } //queue <int> qe; //void bfs(int st)//對節點廣搜 //{ // qe.push(st); // while(cc!=k) // { // int t=qe.front(); // qe.pop(); // // for(int i=0;i<G[t].size();i++) // { // cc++; // ans.push_back(G[t][i].second); // qe.push(G[t][i].first); // if(cc==k) // return; // } // } //} int main() { int u,v; ll w; memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++) { scanf("%d%d%lld",&u,&v,&w); addedge(u,v,w,i); addedge(v,u,w,i); } Dijkstra(1); if(k>=n-1) { printf("%d\n",n-1); for(int i=2;i<=n;i++) { printf("%d ",prem[i]); } } else { int re=n-1; for(int i=2;i<=n;i++) { G[pre[i]].push_back(pair <int, int> (i,prem[i]));//重新根據前驅生成一棵樹 //節點i到節點G[i].f的邊編號為G[i].s //cout<<pre[i]<<' '<<i<<' '<<prem[i]<<endl; } cc=0; dfs(1); printf("%d\n",k); for(int i=0;i<ans.size();i++) { printf("%d ",ans[i]); } } return 0; }