UESTC 1646 穷且益坚,不坠青云之志。 差分约束、Fellman-ford

ProLightsfx 2017-5-28 104 5/28

穷且益坚, 不坠青云之志。差分约束、Fellman-ford

Source

2017 UESTC Training for Graph Theory

UESTC 1646 穷且益坚, 不坠青云之志。  

 

My Solution

题意:求一个有n个元素的数列,满足任意连续p个数的和不小于s,任意连续q个数的和不大于t。

差分约束、Fellman-ford
令sum[i]表示前i项的和(0<=i<=n,sum[0]=0)
那么题目的条件可转化为:
sum[i]-sum[i-p]>=s (p<=i<=n)
sum[i]-sum[i-q]<=t (q<=i<=n)
将第一个不等式取反,得到
sum[i-p]-sum[i]<=-s(p<=i<=n)
于是问题转化为求一系列不等式的解,这是一个典型的差分约束问题。

考虑最短路径的性质,令dis[i]表示从s到i的最短路,则对于图中存在的一条边(u,v),
有dis[v]<=dis[u]+w(u,v),即dis[v]-dis[u]<=w(u,v);
类比不等式,于是可建图,i向i-p引长度为-s的边,i-q向i引长度为t的边。

然后运行bellmanford,如果存在负环,则无解,
否则所得到的最短路的值就是sum[i]的一个解。

时间复杂度 O(VE)
空间复杂度 O(V + E)

 

#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
typedef pair<int, LL> ii;
const int MAXN = 1e3 + 8;
const LL INF = 1e9;
vector sons[MAXN];
LL dis[MAXN];
int cnt[MAXN];
bool inque[MAXN];
queue que;
//O(nlogn)
inline bool SPFA(int n, int src)
{
    for(int i = 0; i <= n; i++){
        dis[i] = INF;
    }
    memset(inque, false, sizeof inque);
    memset(cnt, 0, sizeof cnt);
    dis[src] = 0;
	while(!que.empty()) que.pop();
	que.push(src);
	inque[src] = true;
	for(int i = 1; i <= n; i++){
        que.push(i);
        inque[i] = true;
	}//这样不连通也能跑Bellman-ford
	LL u, v, w, sz, i;
	while(!que.empty()){
        u = que.front();
        que.pop();
        inque[u] = false;
        sz = sons[u].size();
		for(i = 0; i < sz; i++){
			v = sons[u][i].first;
			w = sons[u][i].second;
			if(dis[u] + w < dis[v]){ dis[v] = dis[u] + w; cnt[v]++; if(cnt[v] > n) return false;
				if(!inque[v]){
                    inque[v] = true;
                    que.push(v);
				}
			}
		}
	}
	return true;
}

int main()
{
    #ifdef LOCAL
    freopen("j.txt", "r", stdin);
    //freopen("j.out", "w", stdout);
    int T = 1;
    while(T--){
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    int n, p, q, i;
    LL s, t;
    scanf("%d%d%d%lld%lld", &n, &p, &q, &s, &t);
    for(i = 0; i <= n; i++){ if(i - p >= 0) sons[i].push_back(ii(i-p, -s));
        if(i - q >= 0) sons[i-q].push_back(ii(i, t));
    }
    if(!SPFA(n, 0)) puts("No");
    else{
        printf("Yesn%lld", dis[1]);
        for(i = 2; i <= n; i++){
            printf(" %lld", dis[i] - dis[i-1]);
        }
        putchar('n');
    }



    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}

 


非特殊说明,本博所有文章均为博主原创,未经许可不得转载。

https://www.prolightsfxjh.com/

Thank you!

                                                                                                                                             ------from ProLightsfx

- THE END -

ProLightsfx

11月15日14:16

最后修改:2024年11月15日
0

非特殊说明,本博所有文章均为博主原创,未经许可不得转载。

共有 0 条评论