题解 P6005 [USACO20JAN]Time is Mooney G
Posted dannyxu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P6005 [USACO20JAN]Time is Mooney G相关的知识,希望对你有一定的参考价值。
抢第一篇题解
这题的思路其实就是一个非常简单的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;//输出
}
以上是关于题解 P6005 [USACO20JAN]Time is Mooney G的主要内容,如果未能解决你的问题,请参考以下文章
题解 P3605 [USACO17JAN]Promotion Counting晋升者计数
P3116 [USACO15JAN]会议时间Meeting Time
洛谷P3116 [USACO15JAN]约会时间Meeting Time