2 条题解

  • 0
    @ 2025-10-8 16:57:13
    #include<bits/stdc++.h>
    using namespace std;
    const int N=25, INF=0x3f3f3f3f;
    int n, mlen, fa[N], b[N], cnt, res, ans, d[N][N]; bool v[N];
    struct edge{int x, y, c;} e[2010]; //边的数量开多一点 
    bool cmp(edge e1, edge e2) {return e1.c<e2.c;}
    int findfa(int x) {return fa[x]=((fa[x]==x)? fa[x]: findfa(fa[x]));}
    unordered_map<string, int> mp;
    void dfs(int sum, int k, int m, int p)
    { // sum为答案,k为剩下还没连的连通块,m为已经处理的连通块,p为当前可以选的最小位置 
    	if(sum>=res || (cnt-p+1)<k) return ; //答案没有 res优  或  剩下的连通块全部都处理还不能处理完 k个 
    	if(m==cnt) {res=sum; return ;} //都处理完了,更新答案 
    	if(k>0) //还有剩下的 
    	{
    		for(int i=p; i<=cnt; i++) if(v[i]==0) //没有处理的 
    		{
    			v[i]=1; //标记 
    			dfs(sum+d[i][0], k-1, m+1, i+1); //加上和 Park的距离,未处理-1,已处理+1,位置为当前+1 
    			v[i]=0; //回溯 
    		}
    	}
    	else
    	{
    		for(int i=1; i<=cnt; i++) if(v[i]==0) //没有处理的 
    		{
    			int mi=INF; v[i]=1; //寻找已经和 Park联通的点,和第 i个点距离最小 (mi) 
    			for(int j=1; j<=cnt; j++) 
    				if(v[j]==1) mi=min(mi, d[i][j]);
    			dfs(sum+mi, 0, m+1, 0); //加上最小距离,已经连完,已处理+1,位置为 0(不重要) 
    			v[i]=0; //回溯 
    		}
    	}
    }
    int main()
    {
    	scanf("%d", &n); 
    	mp.clear(); mlen=0; mp["Park"]=0; //用 map来存边 
    	for(int i=1; i<=n; i++)
    	{
    		string a, b; int c; cin>> a>> b>> c;
    		if(!mp.count(a)) mp[a]=++mlen;
    		if(!mp.count(b)) mp[ b ]=++mlen;
    		e[i]={mp[a], mp[ b ], c};
    	}
    	int S; scanf("%d", &S);
    	
    	sort(e+1, e+n+1, cmp); cnt=0;
    	memset(b, 0, sizeof(b)); res=ans=0; //res 存和 Park连的边,ans是连通块之间连的边 
    	for(int i=0; i<=21; i++) fa[i]=i; //每个点都是一个连通块 
    	memset(d, 63, sizeof(d)); //d 初始化无穷大 
    	for(int i=1; i<=n; i++)
    	{
    		int x=findfa(e[i].x), y=findfa(e[i].y);
    		if(y==0) swap(x, y); //因为是双向边所以可以把情况都转成 x=0 
    		if(x==y || (x==0 && b[y]!=0)) continue; // x和 y已经联通 
    		if(x==0) {d[++cnt][0]=e[i].c; b[y]=cnt; res+=e[i].c;} //和 Park连边 
    		else if(b[x]!=0 && b[y]!=0) //两个连通块之间连的边 
    		{
    			int t=min(d[b[x]][b[y]], e[i].c);
    			d[b[x]][b[y]]=d[b[y]][b[x]]=t;
    		}
    		else if(b[x]!=0) {ans+=e[i].c; fa[y]=x;} //把 y并进 x 
    		else if(b[y]!=0) {ans+=e[i].c; fa[x]=y;} //把 x并进 y 
    		else {ans+=e[i].c; fa[y]=x;} 
    		//两个点是分散的,先连起来 (将来一定可以连到 Park,因为每个点都有到 Park的路径) 
    	}
    	
    	memset(v, 0, sizeof(v));
    	if(cnt>S) {res=INF; dfs(0, S, 0, 1);} //连通块数量大于 S,那连通块之间先连起来 
    	printf("Total miles driven: %d\n", ans+res); //输出 
    	return 0;
    }
    
    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e4+10, M=5e5+10, INF=0x3f3f3f3f;
    struct edge{int x, y, c;} e[M];
    bool cmp(edge e1, edge e2) {return e1.c<e2.c;}
    int d[N], fa[N], key[N], tmp[N], mlen;
    int findfa(int x) {return fa[x]=((fa[x]==x)? fa[x]: findfa(fa[x]));}
    unordered_map<string, int> mp;
    bool unite(int x, int y, int c)
    {
    	int tx=findfa(x), ty=findfa(y);
    	if(tx==ty) return 0;
    	if(d[tx]<d[ty]) swap(tx, ty);
    	key[tx]=c; fa[tx]=ty;
    	return 1;
    }
    int main()
    {
    	int n=21, m, S=1, K; scanf("%d", &m); //S代表的是点,K代表的是度数 
    	for(int i=1; i<=n; i++) if(i!=S) fa[i]=i, d[i]=INF;
    	int p=0, tot=0, cnt=0; memset(d, 63, sizeof(d));
    	mp.clear(); mp["Park"]=1; mlen=1; int ans=0, res=0;
    	for(int i=1; i<=m; i++)
    	{
    		string a, b; int c; cin>> a>> b>> c;
    		if(!mp.count(a)) mp[a]=++mlen;
    		if(!mp.count(b)) mp[ b ]=++mlen;
    		if(mp[a]==S) d[mp[ b ]]=min(d[mp[ b ]], c);
    		else if(mp[ b ]==S) d[mp[a]]=min(d[mp[a]], c);
    		else e[++cnt]={mp[a], mp[ b ], c};
    	}
    	n=mlen; scanf("%d", &K);  sort(e+1, e+cnt+1, cmp); 
    	
    	for(int i=1; i<=cnt; i++) if(unite(e[i].x, e[i].y, e[i].c)==1) res+=e[i].c;
    	for(int i=1; i<=n; i++) if(i!=S && findfa(i)==i) p++, res+=d[i], d[i]=INF;
    	for(int i=1; i<=n; i++) if(i!=S && d[i]!=INF) tmp[++tot]=d[i]-key[i];
    	
    	sort(tmp+1, tmp+tot+1); ans=res;
    	for(int i=1; i<=K-p; i++) res+=tmp[i], ans=min(ans, res);
    	printf("Total miles driven: %d\n", ans);
    	return 0;
    }
    
    • 0
      @ 2025-10-8 16:56:51
      #include<bits/stdc++.h>
      using namespace std;
      const int N=25, INF=0x3f3f3f3f;
      int n, mlen, fa[N], b[N], cnt, res, ans, d[N][N]; bool v[N];
      struct edge{int x, y, c;} e[2010]; //边的数量开多一点 
      bool cmp(edge e1, edge e2) {return e1.c<e2.c;}
      int findfa(int x) {return fa[x]=((fa[x]==x)? fa[x]: findfa(fa[x]));}
      unordered_map<string, int> mp;
      void dfs(int sum, int k, int m, int p)
      { // sum为答案,k为剩下还没连的连通块,m为已经处理的连通块,p为当前可以选的最小位置 
      	if(sum>=res || (cnt-p+1)<k) return ; //答案没有 res优  或  剩下的连通块全部都处理还不能处理完 k个 
      	if(m==cnt) {res=sum; return ;} //都处理完了,更新答案 
      	if(k>0) //还有剩下的 
      	{
      		for(int i=p; i<=cnt; i++) if(v[i]==0) //没有处理的 
      		{
      			v[i]=1; //标记 
      			dfs(sum+d[i][0], k-1, m+1, i+1); //加上和 Park的距离,未处理-1,已处理+1,位置为当前+1 
      			v[i]=0; //回溯 
      		}
      	}
      	else
      	{
      		for(int i=1; i<=cnt; i++) if(v[i]==0) //没有处理的 
      		{
      			int mi=INF; v[i]=1; //寻找已经和 Park联通的点,和第 i个点距离最小 (mi) 
      			for(int j=1; j<=cnt; j++) 
      				if(v[j]==1) mi=min(mi, d[i][j]);
      			dfs(sum+mi, 0, m+1, 0); //加上最小距离,已经连完,已处理+1,位置为 0(不重要) 
      			v[i]=0; //回溯 
      		}
      	}
      }
      int main()
      {
      	scanf("%d", &n); 
      	mp.clear(); mlen=0; mp["Park"]=0; //用 map来存边 
      	for(int i=1; i<=n; i++)
      	{
      		string a, b; int c; cin>> a>> b>> c;
      		if(!mp.count(a)) mp[a]=++mlen;
      		if(!mp.count(b)) mp[ b ]=++mlen;
      		e[i]={mp[a], mp[ b ], c};
      	}
      	int S; scanf("%d", &S);
      	
      	sort(e+1, e+n+1, cmp); cnt=0;
      	memset(b, 0, sizeof(b)); res=ans=0; //res 存和 Park连的边,ans是连通块之间连的边 
      	for(int i=0; i<=21; i++) fa[i]=i; //每个点都是一个连通块 
      	memset(d, 63, sizeof(d)); //d 初始化无穷大 
      	for(int i=1; i<=n; i++)
      	{
      		int x=findfa(e[i].x), y=findfa(e[i].y);
      		if(y==0) swap(x, y); //因为是双向边所以可以把情况都转成 x=0 
      		if(x==y || (x==0 && b[y]!=0)) continue; // x和 y已经联通 
      		if(x==0) {d[++cnt][0]=e[i].c; b[y]=cnt; res+=e[i].c;} //和 Park连边 
      		else if(b[x]!=0 && b[y]!=0) //两个连通块之间连的边 
      		{
      			int t=min(d[b[x]][b[y]], e[i].c);
      			d[b[x]][b[y]]=d[b[y]][b[x]]=t;
      		}
      		else if(b[x]!=0) {ans+=e[i].c; fa[y]=x;} //把 y并进 x 
      		else if(b[y]!=0) {ans+=e[i].c; fa[x]=y;} //把 x并进 y 
      		else {ans+=e[i].c; fa[y]=x;} 
      		//两个点是分散的,先连起来 (将来一定可以连到 Park,因为每个点都有到 Park的路径) 
      	}
      	
      	memset(v, 0, sizeof(v));
      	if(cnt>S) {res=INF; dfs(0, S, 0, 1);} //连通块数量大于 S,那连通块之间先连起来 
      	printf("Total miles driven: %d\n", ans+res); //输出 
      	return 0;
      }

      兼容出发点不是1的版本:
      #include<bits/stdc++.h>
      using namespace std;
      const int N=5e4+10, M=5e5+10, INF=0x3f3f3f3f;
      struct edge{int x, y, c;} e[M];
      bool cmp(edge e1, edge e2) {return e1.c<e2.c;}
      int d[N], fa[N], key[N], tmp[N], mlen;
      int findfa(int x) {return fa[x]=((fa[x]==x)? fa[x]: findfa(fa[x]));}
      unordered_map<string, int> mp;
      bool unite(int x, int y, int c)
      {
      	int tx=findfa(x), ty=findfa(y);
      	if(tx==ty) return 0;
      	if(d[tx]<d[ty]) swap(tx, ty);
      	key[tx]=c; fa[tx]=ty;
      	return 1;
      }
      int main()
      {
      	int n=21, m, S=1, K; scanf("%d", &m); //S代表的是点,K代表的是度数 
      	for(int i=1; i<=n; i++) if(i!=S) fa[i]=i, d[i]=INF;
      	int p=0, tot=0, cnt=0; memset(d, 63, sizeof(d));
      	mp.clear(); mp["Park"]=1; mlen=1; int ans=0, res=0;
      	for(int i=1; i<=m; i++)
      	{
      		string a, b; int c; cin>> a>> b>> c;
      		if(!mp.count(a)) mp[a]=++mlen;
      		if(!mp.count(b)) mp[ b ]=++mlen;
      		if(mp[a]==S) d[mp[ b ]]=min(d[mp[ b ]], c);
      		else if(mp[ b ]==S) d[mp[a]]=min(d[mp[a]], c);
      		else e[++cnt]={mp[a], mp[ b ], c};
      	}
      	n=mlen; scanf("%d", &K);  sort(e+1, e+cnt+1, cmp); 
      
      for(int i=1; i&lt;=cnt; i++) if(unite(e[i].x&#44; e[i].y&#44; e[i].c)==1) res+=e[i].c;
      for(int i=1; i&lt;=n; i++) if(i!=S &amp;&amp; findfa(i)==i) p++&#44; res+=d[i]&#44; d[i]=INF;
      for(int i=1; i&lt;=n; i++) if(i!=S &amp;&amp; d[i]!=INF) tmp[++tot]=d[i]-key[i];
      
      sort(tmp+1&#44; tmp+tot+1); ans=res;
      for(int i=1; i&lt;=K-p; i++) res+=tmp[i]&#44; ans=min(ans&#44; res);
      printf("Total miles driven: %d\n"&#44; ans);
      return 0;
      

      }


      </p>
      • 1

      0x60图论(0x62 最小生成树)例题2:野餐规划

      信息

      ID
      1435
      时间
      1000ms
      内存
      10MiB
      难度
      7
      标签
      递交数
      94
      已通过
      21
      上传者