POJ 3621 SPFA

本文介绍一种利用SPFA算法结合二分查找求解图中具有最大点权和与边权和之比的环的方法。通过修改边权并搜索负权环来逼近最优解。

题意:给n个点的点权以及m条有向边,求图中一个 点权和与边权和之比 最大的环的 点权和与边权和之比。

思路:与环有关的可以想到SPFA,

           设点权为c,i到j的边权为w[i][j],

           设答案为ans,点1~p依次连成所求环, 则,

           (c[1] + c[2] + ... + c[p]) / (w[1][2] + w[2][3] + ... + w[p][1]) = ans;

            ans不好直接求,考虑二分答案,若当前判断是否存在 点权和与边权和之比 > t,

            则重新定义从 i 到 j 边权为: w[i][j] * t - c[j],

            此时若存在负权环,则考虑这个环的边权之和,

            (w[1][2] + w[2][3]... + w[p][1]) * t - (c[1] ... + c[p]) < 0

            t < (c[1]  ... + c[p]) / (w[1][2] + w[2][3] ... + w[p][1]) = ans, 即答案一定比 t 大,

            若不存在反之。

            注意最好用%f输出。。。

代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <queue>
#include <cstring>
#include <vector>

#define For(i,j,k) for(int i = j;i <= (int)k;i ++)
#define Set(i,j) memset(i, j, sizeof(i))
#define pb push_back

using namespace std;
const int N = 1010;

vector<int> G[N], w[N];
int n, m, c[N], inq[N];
double d[N];

void Add(int x, int y, int z){
	G[x].pb(y), w[x].pb(z);
}

bool SPFA(double val){
	queue<int> q;
	For(i,0,n) d[i] = 1e18;
	Set(inq, 0);
	inq[1] = -1, d[1] = 0, q.push(1);
	while(!q.empty()){
		int s = q.front(); q.pop();
		inq[s] = -inq[s];
		For(i,0,G[s].size() - 1){
			int v = G[s][i];
			double dis = val * w[s][i] - c[v];
			if(dis + d[s] < d[v]){
				d[v] = dis + d[s];
				if(inq[v] >= 0){
					if(inq[v] >= n) return 1;
					inq[v] = -inq[v] - 1;
					q.push(v);
				}
			}
		}
	}
	return 0;
}

int main(){
	scanf("%d%d", &n, &m);
	For(i,1,n) scanf("%d", &c[i]);
	For(i,1,m){
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		Add(x, y, z);
	}
	double L = 0, R = N, M;
	while(R - L > 1e-4){
		M = (L + R) / 2;
		if(SPFA(M)) L = M;
		else R = M;
	}
	printf("%.2f", M);
	return 0;
}



05-26
### 关于 POJ 3262 的问题描述 POJ 3262 是一个经典的算法竞赛题目,通常涉及动态规划(Dynamic Programming, DP)、贪心策略或其他优化方法。虽然未提供具体题目的详细说明,但从常见的 POJ 题目风格来看,这类问题可能围绕资源分配、路径寻找或序列处理展开。 以下是关于该问题的一些常见解决思路: #### 动态规划的应用 如果问题是基于区间划分或者子集选取,则可以考虑使用动态规划来解决问题。假设输入数据是一个数组 `arr` 或者一组条件集合,可以通过定义状态转移方程实现最优解计算[^1]。 ```python # 示例代码:动态规划模板 def dp_solution(n, data): dp = [0] * (n + 1) # 初始化DP表 for i in range(1, n + 1): dp[i] = max(dp[i - 1], dp[i - 2] + data[i]) # 状态转移逻辑 return dp[n] print(dp_solution(len(data), data)) ``` 此代码片段仅作为参考框架,实际应用需根据题目调整状态定义和边界条件。 #### 图论模型构建 部分情况下,POJ 3262 可能涉及到图结构建模。例如通过构造加权边表示关系矩阵,并借助最短路径算法(如 Dijkstra 或 SPFA)验证可行性[^3]。 ```cpp // C++ 实现示例:SPFA 判断正环 #include <bits/stdc++.h> using namespace std; const int INF = 1e9; int dist[1005]; bool vis[1005]; void spfa(int s, vector<vector<pair<int, int>>> &graph){ queue<int> q; fill(dist, dist+1005, -INF); dist[s]=0; q.push(s); vis[s]=true; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for(auto &[v,w]: graph[u]){ if(dist[v]<dist[u]+w){ dist[v]=dist[u]+w; if(!vis[v]){ vis[v]=true; q.push(v); } } } } } ``` 以上代码展示了如何利用 SPFA 方法检测是否存在满足特定约束的路径组合。 #### 数据预处理技巧 针对大规模测试样例场景下效率瓶颈问题,可引入前缀和、二分查找等高效手段加速运算过程[^4]。 --- ### 总结 综上所述,解答 POJ 3262 应当依据其核心命题方向选定合适的技术路线。无论是采用递推思想还是依赖复杂网络流理论支撑,都需要紧密结合实例特征完成定制化设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值