Codeforces 1076D Edge Deletion(最短路瞎写)
题意 给一个无向简单联通图,删去边,留下最多k条边,问剩下的点里面从1开始的最短路距离不变的点最多怎么构造。
思路 这个思路特别特别简单,要不是我题目读错了我也不至于赛后被官方认定假算法给wa test3了,那我到底是写博客呢还是写博客呢。。。。
【Codeforces 1076D Edge Deletion(最短路瞎写)】我一开始以为是多源最短路的那种题,要求剩下的点到其他点的最短路尽量最少,我说,从最短路树上找个直径呗,然后如果边有多的,那就再加枝杈。结果最后比赛只剩2分钟,我枝杈都不加了,不管了,莽一发,万一过了呢?(肯定被hack,临时风光一下嘛)就过了。然后官方发公告说有些小孩用假算法过了我们等会就抓。第二天果然说的就是我。
实际上的正确思路只要跑一遍Dijkstra,然后从1开始BFS,如果边集大小小于k,就往里加。最后注意下数据范围需要long long,另外这题的数据3e5我估计朴素的Dijkstra会T,不知道有没有卡SPFA的数据。
代码
#include
#include
#include
#include
#include
using namespace std;
/*
* 潘骏同志的Dijsktra板子
* 本版是优化过的堆优化版
*/
struct edge
{
long long from;
long long to;
long long dist;
long long nxt;
long long num;
//其实也可以下标除以2,但我还是存了这个
edge(long long f,long long t,long long d,long long n,long long nu):from(f),to(t),dist(d),nxt(n),num(nu){}
};
vector edges;
//链式前向星,本来想用下标直接当边的编号的,但是无向图两条边事后觉得可以用下标除2
long long egs[300005];
void addedge(long long f,long long t,long long w,long long i)
{
edges.emplace_back(f,t,w,egs[f],i);
egs[f]=edges.size()-1;
edges.emplace_back(t,f,w,egs[t],i);
egs[t]=edges.size()-1;
}
long long dis[300005];
long long pre[300005];
//存储每个节点是被哪个边松弛了
long long lev[300005];
long long n,m;
long long k;
set ans;
long long dijsktra(long long s) {
memset(dis, 0x3f, sizeof(dis));
memset(pre, -1, sizeof pre);
memset(lev, 0, sizeof lev);
dis[s] = 0;
priority_queue, vector >, greater > > qq;
//堆顶是最小元素,按pair的first排序,所以把dis值放first(当年T到怀疑人生。。)
qq.push(make_pair(dis[s], s));
//源点入堆
while (!qq.empty()) {
long long preval = qq.top().first;
long long x = qq.top().second;
//和未优化的版本一样找最小元素
qq.pop();
if (dis[x] < preval) {
//如果目前的值已经比进堆时小了,就没必要再过一遍了,有的题会卡这个时间
continue;
}
for (long long j = egs[x];
j != -1;
j = edges[j].nxt) {
if (dis[edges[j].to] > dis[x] + edges[j].dist) {//一样的松弛操作,但是没有松驰过的点就没必要进堆了
dis[edges[j].to] = dis[x] + edges[j].dist;
pre[edges[j].to] = j;
lev[edges[j].to] = lev[x] + 1;
qq.push(make_pair(dis[edges[j].to], edges[j].to));
}
}
}
long long maxer = 0;
long long maxind = 0;
for (long long i = 1;
i <= n;
i++) {
if (lev[i] > maxer) {//本来拿来求最短路树直径的,现在没用了
maxer = lev[i];
maxind = i;
}
}
return maxind;
}
void bfs(long long s) {
queue qq;
qq.push(s);
while (!qq.empty()) {
long long now = qq.front();
qq.pop();
for (long long i = egs[now];
i != -1;
i = edges[i].nxt) {if (pre[edges[i].to] == i && ans.size() < k) {
//如果边集没满加最短路树上的边
ans.insert(edges[i].num);
qq.push(edges[i].to);
}
}
}
}
int main() {
cin >> n >> m >> k;
memset(egs, -1, sizeof egs);
edges.clear();
for (long long i = 1;
i <= m;
i++) {
long long a, b, c;
cin >> a >> b >> c;
addedge(a, b, c, i);
}
long long s = dijsktra(1);
//long long ender=dijsktra(s);
//本来用来求最短路树直径的,现在p用没有,注释了
ans.clear();
bfs(1);
//从源点1出发BFS最短路树
cout << ans.size() << endl;
for (auto it:ans) {
cout << it << " ";
}
cout << endl;
return 0;
}