Problem - C - Codeforces
目录
题意:
思路:
答疑:
1.为什么反向做呢?
2.为什么是到达点的剩余度数呢?
3.相同路是否可以去重,用个set?
4.如果有多条路相同呢?
参考代码:
题意:
有向图。
从1走到n,可以停一天去封某条路。返回 最优地封完后的 最坏情况。
样例3:
思路:
https://www.cnblogs.com/AWhiteWall/p/13158089.html(参考佬的思路)
方法:
比如到 n点 有 3条路,但是剩下两条比最优的一条要远十几天。那么不如用两天时间把这两条路给封掉。(这是正向想的)
所以干脆算最优时直接加上两天 , 取这几种的最小值即可。(加的这两天就是 n 点的“剩余入度”)
——————
所以我们反向建有向图,反向dijktra,每条路的距离(天数)为 1 加上 到此点的剩余度数。
答疑:
1.为什么反向做呢?
因为我们不要离谱长的边,要直接封掉,那么这些路后面的路都不考虑了。这是“趋近于结果的”贪心。
2.为什么是到达点的剩余度数呢?
我们dijkstra是收集的每个点到起始点( n点 )最短路。 每次操作也是用的当前有的最短路。
本次操作是 n 到达这个点 v 的最短路,也是 v 的最优,结合我们的思路,取最坏(封掉其他路),要加上剩余度数。
3.相同路是否可以去重,用个set?
不可以。因为对于最优解,可能要让这些路都封掉。
4.如果有多条路相同呢?
没关系。等到多条中的最后一条时,这条减的度数最小,也是这种路的最优解。(这几条路不是同一“时空”)
参考代码:
发现我的dijkstra板子感觉可以简写~~(可以看看官方题解的简洁代码)
#define endl "\n"
//#define int long long//不能用set,因为那些长的重复的都要删!!const int maxn = 2e5 + 5;
int arr[maxn];
int d[maxn];
int tmpdis = 1;
struct dis_node//放堆里面比长度,但是想知道端点
{int dis;int next;bool operator < (const dis_node& a){return dis < a.dis;}dis_node(int d, int n){dis = d; next = n;}
};
class cmp
{
public:bool operator()(dis_node a, dis_node b){return a.dis > b.dis;//}
};
void dijkstr(vector<int>& dij, vector<vector<int>>& arr, int ori, int n)
{priority_queue<dis_node, vector<dis_node>, cmp>heap;vector<int>barr(arr.size());int cur = ori;while (1){barr[cur] = 1;for (auto next : arr[cur]){if (dij[next] > dij[cur] + d[next]){dij[next] = dij[cur] + d[next];heap.push(dis_node(dij[next], next));}d[next]--;}while (heap.size()){if (barr[heap.top().next] == 0)break;heap.pop();}if (heap.size() == 0)break;cur = heap.top().next;heap.pop();}
}void solve()
{int n, m;cin >> n >> m;vector<vector<int>>arr(n+1);vector<int>dij(n+1,INT_MAX);dij[n] = 0;for (int i = 0; i < m; i++){int a, b;cin >> a >> b;arr[b].push_back(a);d[a]++;//a的走法,我们是倒着算的,其实正着是a -> b,//我们是用b算的某个a,而且可以认为是当前最小a可走!!!}dijkstr(dij, arr, n, 1);cout << dij[1] << endl;
}