UVA 11478V Halum 二分答案+差分约束系统
2016-05-07 23:21
393 查看
详细翻译版请见白皮书334页
11478 Halum
You are given a directed graph G(V, E) with a set of vertices and edges. Each edge (i, j) that connects
some vertex i to vertex j has an integer cost associated with that edge.
Define the operation Halum(v, d) to operate on a vertex v using an integer d as follows: subtract d
from the cost of all edges that enter v and add d to the cost of every edge that leaves v.
As an example of that operation, consider graph G that has three vertices named (1, 2, 3) and two
edges. Edge (1, 2) has cost -1, and edge (2,3) has cost 1. The operation Halum(2, −3) operates on
edges entering and leaving vertex 2. Thus, edge (1, 2) gets cost -1-(-3)=2 and the edge (2, 3) gets cost
1 + (-3) = -2.
Your goal is to apply the Halum function to a graph, potentially repeatedly, until every edge in the
graph has at least a certain cost that is greater than zero. You have to maximize this cost.
Input
Two space-separated integers per case: V (V ≤ 500) and E (E ≤ 2700). E lines follow. Each line
represents a directed edge using three space-separated integers (u, v, d). Absolute value of cost can be
at most 10000.
Output
If the problem is solvable, then print the maximum possible value. If there is no such solution print ‘No
Solution’. If the value can be arbitrary large print ‘Infinite’
Sample Input
2 1
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1
Sample Output
Infinite
Infinite
3
1
分析:
对于一个点的多次操作相对独立,可以合成一个操作,记为s[x];
题目要求的是最小值的最大值,容易想到二分答案(赤裸裸的暗示啊)。
二分答案最小值x,那么对于每一条边e 一定有:
e.w+s[e.from]-s[e.to]>=x <==> s[e.to]-s[e.from]<=e.w-x ;
其实就是每条边的权重都减小x;
剩下的就是开心的差分啦~~
貌似比较简单,但是wa了6次,主要是因为判定负权回路的条件是进队次数达到n+1次(而不是n次)!!
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<cstdlib>
#define LL long long
#define CLEAR(XXX) memset((XXX),0,sizeof(XXX))
using namespace std;
const int maxn=500+5,maxm=5000+5,inf=1e9;
int m,n;
inline void _read(int &x){
char ch=getchar(); bool mark=false;
for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
if(mark)x=-x;
}
struct Edge{
int from,to,w;
Edge(int from,int to,int w):from(from),to(to),w(w){}
};
struct SPFA{
int n,m;
vector<Edge> edge;
int last[maxm],next[maxm];
LL dist[maxn];
int cnt[maxn];
bool vis[maxn];
void init(int n){
this->n = n;
m=0;
CLEAR(last); CLEAR(next);
edge.clear();
edge.push_back(Edge(0,0,0));
}
void add_edge(int from,int to,int dist){
edge.push_back(Edge(from,to,dist));
m=edge.size()-1;
next[m]=last[from];
last[from]=m;
}
bool solve(int s,int p){
int i;
CLEAR(vis); CLEAR(cnt);
for(i=1;i<=n;i++) dist[i]=inf;
dist[s]=0;
vis[s]=true;cnt[s]++;
queue <int> q;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();vis[x]=false; //及时修改标记
for(i=last[x];i;i=next[i]){
Edge e=edge[i];
e.w-=p;
if(dist[e.from]+e.w<dist[e.to]){
dist[e.to]=dist[e.from]+e.w;
if(!vis[e.to]){
cnt[e.to]++; //统计入队次数,判断负权回路 注意是n+1次!!
if(cnt[e.to]==n+1)return false;
q.push(e.to) ;
vis[e.to]=true;
}
}
}
}
return true;
}
void answer(){
for(int i=1;i<=n;i++)
if(dist[i]>=inf)printf("NoPath\n");
else printf("%I64d\n",dist[i]);
}
};
SPFA solver;
int main(){
int i,x,y,d,l,r,ans=0;
while(cin>>n>>m){
solver.init(n);
for(i=1;i<=m;i++){
_read(x);_read(y);_read(d);
solver.add_edge(x,y,d);
}
for(i=1;i<=n;i++)solver.add_edge(0,i,0);
l=1;r=10001;
if(!solver.solve(0,1)){
puts("No Solution");continue;
}
if(solver.solve(0,r)) {
puts("Infinite");continue;
}
while(l<=r){
int mid=(l+r)>>1;
//w[x]+s[from]-s[to]>=mid; <=> s[to]-s[from]<=w[x]-mid;
if(solver.solve(0,mid)) l=mid+1,ans=max(ans,l);
else r=mid-1;
}
printf("%d\n",r);
}
return 0;
}
11478 Halum
You are given a directed graph G(V, E) with a set of vertices and edges. Each edge (i, j) that connects
some vertex i to vertex j has an integer cost associated with that edge.
Define the operation Halum(v, d) to operate on a vertex v using an integer d as follows: subtract d
from the cost of all edges that enter v and add d to the cost of every edge that leaves v.
As an example of that operation, consider graph G that has three vertices named (1, 2, 3) and two
edges. Edge (1, 2) has cost -1, and edge (2,3) has cost 1. The operation Halum(2, −3) operates on
edges entering and leaving vertex 2. Thus, edge (1, 2) gets cost -1-(-3)=2 and the edge (2, 3) gets cost
1 + (-3) = -2.
Your goal is to apply the Halum function to a graph, potentially repeatedly, until every edge in the
graph has at least a certain cost that is greater than zero. You have to maximize this cost.
Input
Two space-separated integers per case: V (V ≤ 500) and E (E ≤ 2700). E lines follow. Each line
represents a directed edge using three space-separated integers (u, v, d). Absolute value of cost can be
at most 10000.
Output
If the problem is solvable, then print the maximum possible value. If there is no such solution print ‘No
Solution’. If the value can be arbitrary large print ‘Infinite’
Sample Input
2 1
1 2 10
2 1
1 2 -10
3 3
1 2 4
2 3 2
3 1 5
4 5
2 3 4
4 2 5
3 4 2
3 1 0
1 2 -1
Sample Output
Infinite
Infinite
3
1
分析:
对于一个点的多次操作相对独立,可以合成一个操作,记为s[x];
题目要求的是最小值的最大值,容易想到二分答案(赤裸裸的暗示啊)。
二分答案最小值x,那么对于每一条边e 一定有:
e.w+s[e.from]-s[e.to]>=x <==> s[e.to]-s[e.from]<=e.w-x ;
其实就是每条边的权重都减小x;
剩下的就是开心的差分啦~~
貌似比较简单,但是wa了6次,主要是因为判定负权回路的条件是进队次数达到n+1次(而不是n次)!!
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<cstdlib>
#define LL long long
#define CLEAR(XXX) memset((XXX),0,sizeof(XXX))
using namespace std;
const int maxn=500+5,maxm=5000+5,inf=1e9;
int m,n;
inline void _read(int &x){
char ch=getchar(); bool mark=false;
for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
if(mark)x=-x;
}
struct Edge{
int from,to,w;
Edge(int from,int to,int w):from(from),to(to),w(w){}
};
struct SPFA{
int n,m;
vector<Edge> edge;
int last[maxm],next[maxm];
LL dist[maxn];
int cnt[maxn];
bool vis[maxn];
void init(int n){
this->n = n;
m=0;
CLEAR(last); CLEAR(next);
edge.clear();
edge.push_back(Edge(0,0,0));
}
void add_edge(int from,int to,int dist){
edge.push_back(Edge(from,to,dist));
m=edge.size()-1;
next[m]=last[from];
last[from]=m;
}
bool solve(int s,int p){
int i;
CLEAR(vis); CLEAR(cnt);
for(i=1;i<=n;i++) dist[i]=inf;
dist[s]=0;
vis[s]=true;cnt[s]++;
queue <int> q;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();vis[x]=false; //及时修改标记
for(i=last[x];i;i=next[i]){
Edge e=edge[i];
e.w-=p;
if(dist[e.from]+e.w<dist[e.to]){
dist[e.to]=dist[e.from]+e.w;
if(!vis[e.to]){
cnt[e.to]++; //统计入队次数,判断负权回路 注意是n+1次!!
if(cnt[e.to]==n+1)return false;
q.push(e.to) ;
vis[e.to]=true;
}
}
}
}
return true;
}
void answer(){
for(int i=1;i<=n;i++)
if(dist[i]>=inf)printf("NoPath\n");
else printf("%I64d\n",dist[i]);
}
};
SPFA solver;
int main(){
int i,x,y,d,l,r,ans=0;
while(cin>>n>>m){
solver.init(n);
for(i=1;i<=m;i++){
_read(x);_read(y);_read(d);
solver.add_edge(x,y,d);
}
for(i=1;i<=n;i++)solver.add_edge(0,i,0);
l=1;r=10001;
if(!solver.solve(0,1)){
puts("No Solution");continue;
}
if(solver.solve(0,r)) {
puts("Infinite");continue;
}
while(l<=r){
int mid=(l+r)>>1;
//w[x]+s[from]-s[to]>=mid; <=> s[to]-s[from]<=w[x]-mid;
if(solver.solve(0,mid)) l=mid+1,ans=max(ans,l);
else r=mid-1;
}
printf("%d\n",r);
}
return 0;
}
相关文章推荐
- mybatis xml文件中大于小于符号解释
- 动物园的猴子
- 值得推荐的C/C++框架和库
- [BZOJ2875] [NOI2012] 随机数生成器 - 矩阵快速幂
- HTTPS原理
- Java多线程编程
- 南阳OJ上的一个题
- 20145212 实验五《Java网络编程》
- hdu 1301(最小生成树)
- 3、struts2 默认配置、数据处理的集中方式、请求数据封装、日期转换器
- HDU 5667 Sequence(矩阵快速幂+费马小定理)
- Android中Shape 和 Selector的用法
- Linux下Nagios的安装与配置
- 搜狗笔试:有两个数,A和B,六种操作分别是+12,-12,+7,-7,+5,-5。A经过若干次操作,变成B
- C++实验5--数组分离
- 步入社会
- 百度悄然整改 搜索界面首页满满的全是正宗医院
- 百度悄然整改 搜索界面首页满满的全是正宗医院
- HDU 2053 Switch Game(数学题)
- set and Sequence theory