1,cf Omkar and Heavenly Tree;2,acwing 1127 香甜的黄油;3,acwing 1126 最小花费;
1,Omkar and Heavenly Tree
题意:给你n个节点和m个限制,建一棵符合条件的树;m<n,m个限制是给出a,b,c三个节点,b不能出现在a到c的简单路径上;
思路:m<n,所以给出的限制一定不会包含所有的节点,那么我们就可以用未给出的b节点来做根,它一定满足所有要求;然后把其他的节点都连向它即可;
- #pragma GCC optimize(2)
- #include<bits/stdc++.h>
- #define rep1(i,a,n) for( int i=a;i<n;++i)
- #define rep2(i,a,n) for( int i=a;i<=n;++i)
- #define per1(i,n,a) for( int i=n;i>a;i--)
- #define per2(i,n,a) for( int i=n;i>=a;i--)
- #define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
- #define memset(a,i,b) memset((a),(i),sizeof (b))
- #define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
- #define pro_q priority_queue
- #define pb push_back
- #define pf push_front
- #define endl "\n"
- #define lowbit(m) ((-m)&(m))
- #define YES cout<<"YES\n"
- #define NO cout<<"NO\n"
- #define Yes cout<<"Yes\n"
- #define No cout<<"No\n"
- #define yes cout<<"yes\n"
- #define no cout<<"no\n"
- #define yi first
- #define er second
- using namespace std;
- typedef pair<long long,long long>PLL;
- typedef long long LL;
- typedef pair<int,int> PII;
- typedef pair<int,PII> PIII;
- typedef double dob;
- const int N=1e5+10;
- int p[N];
- void solve()
- {
- int n,m;
- cin>>n>>m;
- memset(p,0,p);
- while(m--)
- {
- int a,b,c;
- cin>>a>>b>>c;
- p[b]=1;
- }
- int root;
- rep2(i,1,n)
- {
- if(p[i]==0)
- {
- root=i;
- break;
- }
- }
- rep2(i,1,n)
- {
- if(i!=root)
- {
- cout<<i<<" "<<root<<endl;
- }
- }
- }
- signed main()
- {
- quick_cin();
- int T;
- cin>>T;
- while(T--)solve();
- return 0;
- }
2,香甜的黄油;
很明显,这是一个多源最短路问题;
但是floyed算法n^3会tle,考虑其他做法;
朴素版dijkstra:n^3;tle;
堆优化版dijkstra:n*(mlongn);10^7的复杂度,不会tle;
spfa:n*m;10^6;更不会tle了;(spfa一般情况是O(m),但是可能会被卡成O(n*m));
所以用spfa来做此题;
简单复习下spfa算法:
- #pragma GCC optimize(2)
- #include<bits/stdc++.h>
- #define rep1(i,a,n) for( int i=a;i<n;++i)
- #define rep2(i,a,n) for( int i=a;i<=n;++i)
- #define per1(i,n,a) for( int i=n;i>a;i--)
- #define per2(i,n,a) for( int i=n;i>=a;i--)
- #define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
- #define memset(a,i,b) memset((a),(i),sizeof (b))
- #define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
- #define pro_q priority_queue
- #define pb push_back
- #define pf push_front
- #define endl "\n"
- #define lowbit(m) ((-m)&(m))
- #define YES cout<<"YES\n"
- #define NO cout<<"NO\n"
- #define Yes cout<<"Yes\n"
- #define No cout<<"No\n"
- #define yes cout<<"yes\n"
- #define no cout<<"no\n"
- #define yi first
- #define er second
- using namespace std;
- typedef pair<long long,long long>PLL;
- typedef long long LL;
- typedef pair<int,int> PII;
- typedef pair<int,PII> PIII;
- typedef double dob;
- const int N=1e4+10;
- int e[N],ne[N],w[N],idx,h[N];
- int n,p,c;
- int dist[N];
- int st[N];
- int id[N];
- void add(int a,int b,int c)
- {
- w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
- int spfa(int op)
- {
- memset(dist,0x3f,dist);
- queue<int>q;
- dist[op]=0;
- q.push(op);
- st[op]=1;
- while(q.size())
- {
- int t=q.front();q.pop();
- st[t]=0;
- for(int i=h[t];~i;i=ne[i])
- {
- int j=e[i];
- if(dist[j]>dist[t]+w[i])
- {
- dist[j]=dist[t]+w[i];
- if(!st[j])
- {
- q.push(j);
- st[j]=1;
- }
- }
- }
- }
- int res=0;
- rep2(i,1,n)
- {
- int j=id[i];
- if(dist[j]==0x3f3f3f3f)return INT_MAX;
- res+=dist[j];
- }
- return res;
- }
- signed main()
- {
- quick_cin();
- memset(h,-1,h);
- cin>>n>>p>>c;
- rep2(i,1,n)cin>>id[i];
- while(c--)
- {
- int a,b,w;
- cin>>a>>b>>w;
- add(a,b,w),add(b,a,w);
- }
- int ans=INT_MAX;
- rep2(i,1,p)ans=min(ans,spfa(i));
- cout<<ans;
- return 0;
- }
3,最小花费;
思路:,将转账看成是在图上走过一条边,这条边的权是1 − z % ,并且每走过一条边,就乘上这个权值。那么相当于要问,从A 走到B 的最大权值乘积是多少。
- #pragma GCC optimize(2)
- #include<bits/stdc++.h>
- #define rep1(i,a,n) for( int i=a;i<n;++i)
- #define rep2(i,a,n) for( int i=a;i<=n;++i)
- #define per1(i,n,a) for( int i=n;i>a;i--)
- #define per2(i,n,a) for( int i=n;i>=a;i--)
- #define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
- #define memset(a,i,b) memset((a),(i),sizeof (b))
- #define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
- #define pro_q priority_queue
- #define pb push_back
- #define pf push_front
- #define endl "\n"
- #define lowbit(m) ((-m)&(m))
- #define YES cout<<"YES\n"
- #define NO cout<<"NO\n"
- #define Yes cout<<"Yes\n"
- #define No cout<<"No\n"
- #define yes cout<<"yes\n"
- #define no cout<<"no\n"
- #define yi first
- #define er second
- using namespace std;
- typedef pair<long long,long long>PLL;
- typedef long long LL;
- typedef pair<int,int> PII;
- typedef pair<int,PII> PIII;
- typedef double dob;
- const int N=2010,M=2e5+10,INF=0x3f3f3f3f;
- int n,m;
- dob d[N][N];
- int s,e;
- dob dist[N];
- int st[N];
- void dijkstra()
- {
- dist[s]=1;
- rep2(i,1,n)
- {
- int ver=-1;
- rep2(j,1,n)
- {
- if(!st[j]&&(ver==-1||dist[j]>dist[ver]))ver=j;
- }
- st[ver]=1;
- rep2(j,1,n)dist[j]=max(dist[j],dist[ver]*d[ver][j]);
-
- }
- }
- signed main()
- {
- quick_cin();
- cin>>n>>m;
- while(m--)
- {
- int a,b,w;
- cin>>a>>b>>w;
- dob t=(100.0-w)/100;
- d[a][b]=d[b][a]=max(d[a][b],t);
- }
- cin>>s>>e;
- dijkstra();
- cout<<fixed<<setprecision(8)<<100/dist[e];
- return 0;
- }
然后关于单源最值的问题;
spfa可以求乘积最大和最小,也可以求加法最大和最小,原理是其是松弛操作不是贪心;
而dijkstra可以求加法最小(正权边,)乘积最大;