抢第一篇题解
这题的思路其实就是一个非常简单的dijkstra,如果跑到第一个点的数据不能更新的时候就输出
很多人不知道要跑多少次才停.其实这题因为答案要减去 T*c^2,而每条边的值 <= 1000,稍微推一下就可以发现这个程序最多跑1000次.
所以,简单暴力的做法就是暴力写1000次dijkstra (01dij或者二维1000*1000都可以).这个方法当然可以优化,但是没有超时谁理他呢
现在剩下一个小问题(如果没有经过的点,我们不能更新连同他的路).那么怎么办呢?
摆在眼前的路有两条.第一:到所有点的初始值设成-1跑.如果目前的点的值为-1就证明他没有被经过,所以需要跳过
第二:做一个vis,记录每次经过并且以前没有经过过的点.这里我用的是queue,记录所有这一次被拿到的点.
注意不要马上更新,因为如果你马上更新就会出现没有经过的点被更新了
01的意义就是保证所有点更新的都是之前更新过但这一次没有更新的,保证不会出现一条边被更新很多次的情况
话不多说,上代码
#include <iostream> #include <algorithm> #include <math.h> #include <queue> using namespace std; int dp[1005][2],head[100005],tot = 0,n,m,c, cost[1005],ans=0,vis[1005]; struct Edge{ int from, to,next; }edge[100005]; void add(int f,int t){ edge[++tot].from = f; edge[tot].to = t; edge[tot].next = head[f]; head[f] = tot; } void setIO(string name) { freopen((name+".in").c_str(),"r",stdin); freopen((name+".out").c_str(),"w",stdout); ios_base::sync_with_stdio(0); } //以上不解释 void dij(int curr){ queue<int> q;//记经过的边 for (int i=1;i<=n;i++){ if (!vis[i]) continue;//如果没有经过就不跑 for (int j=head[i];j;j=edge[j].next){ if (!vis[edge[j].to]) q.push(edge[j].to);//没经过就加进queue待会更新 dp[edge[j].to][curr%2] = max(dp[edge[j].from][(curr+1)%2]+cost[edge[j].to],dp[edge[j].to][curr%2]); //要去的点的值现在的点的值+那个点的权值. } } while(!q.empty()){vis[q.front()] = true;q.pop();} //将所有经过的点的vis设成true ans = max(ans,(int)(dp[1][curr%2]-c*pow(curr,2))); //更新答案 } int main(){ // setIO("time"); cin >> n >> m >> c; for (int i=1;i<=n;i++) cin >> cost[i]; for (int i=0;i<m;i++){ int a,b; cin >> a >> b; add(a,b);//连边,如果要转化为权值问题只需将权值设为cost[b]就行 } vis[1] = true;//将初始点设为已经过 for (int i=1;i<1000;i++){ dij(i);//跑1000次 } cout << ans;//输出 }
来源:https://www.cnblogs.com/DannyXu/p/12232731.html