首页 > 其他分享 >Living-Dream 系列笔记 第42期

Living-Dream 系列笔记 第42期

时间:2024-03-02 16:58:01浏览次数:22  
标签:Living pq int 42 vis push now Dream dis

T1

枚举流量对于花费跑 dijkstra 并取比值的 \(\max\) 即可。

关于为什么枚举流量不一定当前最优的问题,因为最优解的流量总在枚举范围内,所以无需考虑当前是否最优。

#include<bits/stdc++.h>
using namespace std;

int n,m,ans;
int dis[100031];
bool vis[100031];
struct Edge{ int v,c,f; };
vector<Edge> G[200031];
struct Node{
	int u,c,f;
	bool operator < (const Node &b) const{
		return c>b.c;
	}
};

void dijkstra(int s,int x){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis)),dis[s]=0;
	priority_queue<Node> pq; pq.push({s,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(i.f>=x&&dis[i.v]>dis[now.u]+i.c)
				dis[i.v]=dis[now.u]+i.c,
				pq.push({i.v,dis[i.v]}); 
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=1,u,v,c,f;i<=m;i++)
		cin>>u>>v>>c>>f,G[u].push_back({v,c,f}),G[v].push_back({u,c,f});
	int l=1,r=1000;
	while(l<=r){
		int mid=(l+r)>>1;
		dijkstra(1,mid);
		if(dis[n]!=0x3f3f3f3f) l=mid+1,ans=1000000*mid/dis[n];
		else r=mid-1;
	}
	cout<<ans;
	return 0;
} 

T2

考虑 dp,在松弛操作时进行转移。

当 dijkstra 发现一条新的最短路点时,直接继承即可。

否则如果发现邻接点 \(dis\) 值与当前最优值相等,加上当前点的 \(dp\) 值即可。

#include<bits/stdc++.h>
using namespace std;

const int MOD=100003,N=1000031;
int n,m,ans;
int dis[N],cnt[N];
bool vis[N];
vector<int> G[N<<1];
struct Node{
	int u,w;
	bool operator < (const Node &b) const{
		return w>b.w;
	}
};

void dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	cnt[1]=1,dis[1]=0;
	priority_queue<Node> pq; pq.push({1,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i]>dis[now.u]+1)
				dis[i]=dis[now.u]+1,
				cnt[i]=cnt[now.u],
				pq.push({i,dis[i]});
			else if(dis[i]==dis[now.u]+1)
				cnt[i]=(cnt[i]+cnt[now.u])%MOD;
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=1,u,v;i<=m;i++)
		cin>>u>>v,G[u].push_back(v),G[v].push_back(u);
	dijkstra();
	for(int i=1;i<=n;i++) cout<<cnt[i]%MOD<<'\n';
	return 0;
} 

T3

题意可转化为求免费完 \(k\) 对之后最大边权的最小值。

一眼二分。

考虑在 check 中重建图,令原边权 \(>mid\) 的边边权为 \(1\),\(<mid\) 的边边权为 \(0\)。

然后跑一边 dijkstra 求出需要免费的点对,

若数量 \(\le k\),则猜小,否则猜大即可。

#include<bits/stdc++.h>
using namespace std;

const int N=1031,M=10031;
int n,m,k,ans;
int dis[N];
bool vis[N];
struct P{ int a,b,l; }p[M];
struct E{ int v,w; };
vector<E> G[M];
struct Node{
	int u,w;
	bool operator < (const Node &b) const{
		return w>b.w;
	}
};

void dijkstra(){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	priority_queue<Node> pq; pq.push({1,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis[i.v]>dis[now.u]+i.w)
				dis[i.v]=dis[now.u]+i.w,
				pq.push({i.v,dis[i.v]});
		}
	}
}
bool check(int x){
	for(int i=1;i<=n;i++) G[i].clear();
	for(int i=1;i<=m;i++)
		G[p[i].a].push_back({p[i].b,(p[i].l>x)}),
		G[p[i].b].push_back({p[i].a,(p[i].l>x)});
	dijkstra();
	return dis[n]<=k;
}

int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++) cin>>p[i].a>>p[i].b>>p[i].l;
	int l=0,r=1e6+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid;
	}
	if(r==1e6+1) cout<<-1;
	else cout<<r;
	return 0;
} 

作业 T1

我们跑两遍 dijkstra,求得 \(1,n\) 到其他点的最短路,记为 \(x_i,y_i\)。

于是答案即为 \(\min(T,\max\{x_i+y_j+1\})\)。

直接算是 \(O(n \log n+n^2)\) 的,T 飞。

于是对于升序的 \(x_i\),下面有两个引理:

  • 引理 \(1\):对于每个 \(x_i\),仅需考虑其右边的 \(y_i\)。

证明:

若 \(j<i\),则有 \(x_i+y_j \ge x_j+y_j \ge T\),其不影响答案。

证毕

  • 引理 \(2\):对于每个 \(x_i\),仅需考虑 \(y_{i+1}\)。

证明:

若 \(y_{i+1} \ge y_i\),则有 \(x_i+y_{i+1} \ge x_i+y_i \ge T\),说明考虑 \(j \ge i+1\) 的情况均对答案无影响。

否则说明 \(y_i\) 降序,则最大值一定出现在 \(y_{i+1}\)。

证毕

综上,答案即为 \(\min(T,\max\{x_i+y_{i+1}+1\})\)。

时间复杂度 \(O(n \log n + n)\)

#include<bits/stdc++.h>
using namespace std;

const int N=2000031;
int n,m,k,ans,p[N];
int dis1[N],disn[N];
bool vis[N];
vector<int> G[N<<1];
struct Node{
	int u,w;
	bool operator < (const Node &b) const{ return w>b.w; }
};
bool cmp(int x,int y){ return dis1[x]<dis1[y]; }

void dijkstra_1(){
	memset(vis,0,sizeof(vis));
	memset(dis1,0x3f,sizeof(dis1)),dis1[1]=0;
	priority_queue<Node> pq; pq.push({1,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(dis1[i]>dis1[now.u]+1)
				dis1[i]=dis1[now.u]+1,
				pq.push({i,dis1[i]});
		}
	}
}
void dijkstra_n(){
	memset(vis,0,sizeof(vis));
	memset(disn,0x3f,sizeof(disn)),disn[n]=0;
	priority_queue<Node> pq; pq.push({n,0});
	while(!pq.empty()){
		Node now=pq.top(); pq.pop();
		if(vis[now.u]) continue; vis[now.u]=1;
		for(auto i:G[now.u]){
			if(disn[i]>disn[now.u]+1)
				disn[i]=disn[now.u]+1,
				pq.push({i,disn[i]});
		}
	}
}

int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++) cin>>p[i];
	for(int i=1,u,v;i<=m;i++) cin>>u>>v,G[u].push_back(v),G[v].push_back(u);
	dijkstra_1(),dijkstra_n(),sort(p+1,p+k+1,cmp);
	for(int i=1;i<k;i++) ans=max(ans,dis1[p[i]]+disn[p[i+1]]+1);
	ans=min(ans,dis1[n]),cout<<ans;
	return 0;
}

标签:Living,pq,int,42,vis,push,now,Dream,dis
From: https://www.cnblogs.com/XOF-0-0/p/18048830

相关文章

  • Living-Dream 系列笔记 第44期
    比赛链接T1\(100\to10\)。错因:01背包转移方程写错,没有取\(\max\)。并查集合并错写成将u,v而非fnd(u),fnd(v)合并。#include<bits/stdc++.h>usingnamespacestd;intn,m,w;intc[10031],d[10031];intfa[10031];intdp[10031];intfnd(intx){return......
  • Living-Dream 系列笔记 第41期
    稍微讲一下dijkstraqwq。dijkstra、bellman-ford(orspfa)、bfs的区别:dijkstra以点为研究对象;bellman-ford/spfa则以边为研究对象;而bfs可以看作边权为\(1\)(or全都相同)的dijkstra,因此它可以用队列实现。dijkstra的具体实现:将所有点分为两类(黑点/白点),......
  • Living-Dream 系列笔记 第40期
    T1bf的做法是\(n\)次floyd,实测可以卡过。然后我们发现当点\(u\)为重要点时,当且仅当存在\((a,b)\)使得\(u\)为它们的唯一中转点。于是我们令\(vis_{i,j}\)表示\((i,j)\)的唯一中转点,接着在floyd的松弛操作中若能松弛则更新其为当前中转点\(k\),否则若没有更优......
  • Living-Dream 系列笔记 第39期
    T1一头牛能确定关系,当且仅当它能到达/被到达除自己外的所有牛。于是我们建出有向图,跑floyd传递闭包,然后对于每个点统计他能到达的点数是否为\(n-1\)即可。#include<bits/stdc++.h>usingnamespacestd;intn,m,ans;intdp[131][131];vector<int>G[4531];voidfl......
  • Living-Dream 周考总结 第3期
    Link,第四场没打。T1\(100\),没挂分。\(\operatorname{lcm}(x,y)=\dfrac{x}{\gcd(x,y)}\timesy\)#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ //freopen("as01.in","r",stdin); //freopen("as0......
  • Living-Dream 周考总结 第4期
    Link。T1\(100\),没挂分。依题计算即可。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ //freopen("as01.in","r",stdin); //freopen("as01.out","w",stdout); ios::sync_with_stdio(0); ......
  • Living-Dream 周考总结 第1期
    Link。T1依题计算即可,\(O(1)\)。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ ios::sync_with_stdio(0); doublen;cin>>n,n=ceil(n/5.0); cout<<setprecision(2)<<fixed; if(n<=100)cout<<0.58......
  • Living-Dream 周考总结 第2期
    Link,第二场没打。T1\(100\),没挂分。依题计算即可,\(O(1)\)。#include<bits/stdc++.h>usingnamespacestd;doublen,a,b;intmain(){ //freopen("as01.in","r",stdin); //freopen("as01.out","w",stdout); cin>>n>&......
  • ABC342
    Clink我们可以把所有字母都存上,代表换到最后这个字母换成什么了,当然最开始就是它本身。那么,把\(c\)改成\(d\)的时候,就只要把所有等于\(c\)的都改成\(d\)就行了。点击查看代码#include<bits/stdc++.h>usingnamespacestd;intn,q;chars[200005];inta[30];signed......
  • p3426-solution
    P3426Solutionlink考虑dp。设\(dp_i\)表示至\(i\)的字符串的答案。KMP求出nxt数组,那么显然\(dp_i\)要么等于\(i\)要么等于\(dp_{nxt_i}\)。什么时候\(dp_i\)等于\(dp_{nxt_i}\)呢?这时这个字符串一定由一个与\(nxt_i\)有相同\(dp\)值的前缀再印上一个bo......