【D - Silver Cow Party】

80 篇文章 0 订阅
80 篇文章 0 订阅

思路:

  • 正权,有向图,从每个点走到终点再返回是一条路,找所有N-1条路(N个点)中的最大值。
  • 自然想到可用Floyd-Warshall,也不出意料TLE
  • Marvis code的BLOG找到正解:将每个点到定点的路径反向,转化为单源点到全图。此操作通过邻接矩阵的转置来实现。

注意:

  1. 多源点单终点类问题:通过对 mp[i][j] 进行矩阵转置解题。注意具体i,j的操作(如果 j1 开始,相当于转置了两次)。
​for(int i=1;i<=N;i++){
		for(int j=i+1;j<=N;j++){
			int temp = mp[i][j];
			mp[i][j] = mp[j][i];
			mp[j][i] = temp;
		}
	}
  1. 数组作为参数传递有两种方法:int dis[],或者 int * dis
  2. 数组作为参数传递时,函数中 sizeof(dis) == 1,为防止错误,尽量不在子函数中使用 memset

代码:

  • Floyd:TLE
#include <iostream>
#include <algorithm>
#include <cstring>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int mp[maxn][maxn];
int N,M,X;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>N>>M>>X;
	memset(mp,INF,sizeof(mp));
	for(int i=1;i<maxn;i++){
		mp[i][i] = 0;
	}
	for(int i=1;i<=M;i++){
		int A,B,T;
		cin>>A>>B>>T;
		mp[A][B] = min(mp[A][B] , T);
	}
	for(int k=1;k<=N;k++)
		for(int i=1;i<=N;i++)
			for(int j=1;j<=N;j++)
				mp[i][j] = min(mp[i][k] + mp[k][j] , mp[i][j]);
	int ans = 0; 
	for(int i=1;i<=N;i++){
		if(mp[i][X] == INF || mp[X][i] == INF)
			continue;
		ans = max(ans , mp[i][X] + mp[X][i]);
	}
	cout<<ans<<endl;
	return 0;
}
  • Dijkstra:235ms 4676kB
//235ms		4676kB 


#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1005;

int mp[maxn][maxn];
int dis_back[maxn];
int dis_go[maxn];
bool vis[maxn];
int N,M,X;
int ans=0;
struct node{
	int id;
	int dis;
	node(int id,int dis) : id(id) , dis(dis) {} ;
	friend bool operator > (const node & a,const node & b)
	{
		return a.dis > b.dis;
	} 
};
priority_queue<node , vector<node> , greater<node> > Q;
void IJK(int dis[]){
	//memset(dis,INF,sizeof(dis));数组作为函数参数,此时不能用memset,sizeof(dis) == 1
	for(int i=1;i<maxn;i++)
		dis[i] = INF;
	memset(vis,0,sizeof(vis));
	Q.push(node(X,0));dis[X] = 0;
	while(Q.size()){
		node cur = Q.top();Q.pop();
		if(vis[cur.id])
			continue;
		vis[cur.id] = true;
		for(int i=1;i<=N;i++){
			if(vis[i])
				continue;
			if(dis[i] > dis[cur.id] + mp[cur.id][i]){
				dis[i] = dis[cur.id] + mp[cur.id][i];
				Q.push(node(i,dis[i]));
			}
		}
	}
	return ;
}

int main(){
	cin>>N>>M>>X;
	memset(mp,INF,sizeof(mp));
	for(int i=0;i<maxn;i++)
		mp[i][i] = 0;
	for(int i=1;i<=M;i++){
		int A,B,T;
		cin>>A>>B>>T;
		mp[A][B] = min(mp[A][B] , T);
	}
	IJK(dis_back);//BACK_ROUTE
	for(int i=1;i<=N;i++){
		for(int j=i+1;j<=N;j++){
			int temp = mp[i][j];
			mp[i][j] = mp[j][i];
			mp[j][i] = temp;
		}
	}
	IJK(dis_go); 
	for(int i=1;i<=N;i++){
		if(dis_go[i] == INF || dis_back[i] == INF)
			continue;
		ans = max(ans , dis_go[i] + dis_back[i]);
	}
	cout<<ans<<endl;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值