Week8 作业

A-区间选点

在这里插入图片描述解题过程
每个未知数对应图中的一个顶点 ,把所有的不等式都化成图中的一条边,xi-xj<=y 就是有向边<i,j>权值为y。求单源最短路可以得到最大解(无负权回路),如果是xi-xj>=y 就是有向边<j,i>权值为y,求单源最长路可以得到最小解(无正权回路)
这道题需要找最小解,以最小的点作为起点,最大的点作为终点,设sum[i]为区间[0,i]中的点数,相邻整数之间的点数需要满足-1<=sum[i]-sum[i+1]<=0;
求取最长路后输出0到最大数之间的点数,既是最少要选的点数。
vector用时比较长虽然比较方便,还是习惯一下向前星比较好。

#include <iostream>
#include<algorithm> 
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
struct wedge{
	int v;
	int w;
}; 
vector<wedge>g[50010];
 void add(int u,int v,int w  )
 { wedge e;
   e.v=v;
   e.w=w;
   g[u].push_back(e);
 	
 }
 
int dis[50010],inq[50010],inf=600000000;
 int maxn=0;int minn=50010;
 
 void spfa(int s)
 { queue<int >q;
   for(int i=s;i<=maxn;i++)
   { dis[i]=-inf;
     inq[i]=0;
   }
   q.push(s);
   inq[s]=1;dis[s]=0;
   while(!q.empty())
   { int u=q.front();
     q.pop();
     inq[u]=0;
     for(int i=0;i<g[u].size();i++)
     {int v=g[u][i].v;
      int w=g[u][i].w;
      if(dis[v]<dis[u]+w)
     	{ dis[v]=dis[u]+w;
     	  if(inq[v]!=1 )
		   {inq[v]=1;
		    q.push(v);
			   }	
		 }	
	 }
		} 	
 }
int main(int argc, char** argv) {
	int n;
	int u,v,w;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{scanf("%d%d%d",&u,&v,&w);
	 add(u,v+1,w);
	 maxn=max(maxn,v+1);
	 minn=min(minn,u);	
	}
	for(int i=minn;i<maxn;i++)
	{add(i,i+1,0);
	 add(i+1,i,-1);
	}
	spfa(minn);
	cout<<dis[maxn];
	
	return 0;
}

B - 猫猫向前冲

在这里插入图片描述
解题过程
拓扑排序上学期学过比较熟悉,就是从入度为零的点开始,将他们全部入队,再将与其邻接的点的入度减1如果为零就入队,直到队列为空如果没有形成环路则得到拓扑序列。因为需要将编号小的排在前面所以使用优先级队列,用普通队列储存答案。
居然没有看到多组数据……

#include <iostream> 
#include<vector>
#include<cmath>
#include<queue>
#include <stdio.h>
#include<utility>
#include <cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
vector<int >g[510];
 void add(int u,int v   )
 {  
   g[u].push_back(v);
 	
 }
 int in_deg[510];
priority_queue<int > q; 
queue<int> qans;
void toposort(int n)
{ 
  
  for(int i=1;i<=n;i++)
  {if(in_deg[i]==0)
   q.push(-i);
  }
	while(!q.empty())
	{ int u=-q.top();
	    q.pop();
		qans.push(u);
		for(int i=0;i<g[u].size();i++)
		{ int v=g[u][i];
		  if(--in_deg[v]==0)
		  q.push(-v);
			
		}
	}
}
int main(int argc, char** argv) {
	int n,m,a,b;
	while(scanf("%d%d",&n,&m)!=EOF)
	{memset(in_deg,0,sizeof(in_deg));
	 for(int i=0;i<=n;i++)
	 g[i].clear();
	 
	for(int i=0;i<m;i++)
 	{scanf("%d%d",&a,&b); 
		add(a,b);
		in_deg[b]++;
	}
	toposort(n);
	while(!qans.empty())
	{ cout<<qans.front();
	  qans.pop();
	  if(qans.size()!=0)
	  cout<<" ";	
	}
	cout<<endl;
		
	}
	return 0;
}

C - 班长竞选

在这里插入图片描述
解题过程
好难啊,虽然在抄模板,还把模板抄错还找不出来……最后的不忽略行末空格怎么输出还想不出来,脑子都开始掉锈了。
在有向图G中,如果两点互相可达,则称这两个点强连通,如果G中任意两点互相可达,则称G是强连通图。
Kosaraju算法
1、从点1开始进行DFS,每次在DFS回溯的过程中进行标记,得到一个后序遍历的顺序的表。
2、对反图g2按步骤1中得到的表从后往前进行DFS遍历。使用了多少次的DFS,就有多少个强联通分量。
dcnt-dfs序计数,scnt-scc计数,dfn[i] dfs后序列中第i个点,c[i]-i号点所在ssc编号
缩点
将一个ssc看成一个点,用g储存该图,遍历原图的每一条边如果边的两点不在同一ssc则向g加入该边。
票会传递所以答案一定在出度为0的点中也就是反图入度为0的点,搞错了出入度结果用样例试一直在输出0。dfs计算票数,就是每个相连接的ssc中点的个数(用num储存)的和,保存最大值,输出学生编号时输出总票数与最大票数相等的ssc点中的所有点。

#include <iostream> 
#include<vector>
#include<cmath>
#include<queue>
#include <stdio.h>
#include<utility>
#include <cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
vector<int >g1[5100],g2[5100],g[5100];
int n,m;
int c[5100],vis2[5100],dfn[5100],num[5100],sum[5100],vis[5100],indeg[5100],dcnt,scnt;
 void add1(int u,int v)
 {  
   g1[u].push_back(v);
 	g2[v].push_back(u);
 }
 
 void dfs1(int x)
 { vis[x]=1;
   for(int i=0;i<g1[x].size();i++)
   { if(!vis[g1[x][i]])
   	   dfs1(g1[x][i]);
   	  
   }
 	dfn[++dcnt]=x; 
 }
  void dfs2(int x)
 { c[x]=scnt;
   for(int i=0;i<g2[x].size();i++)
   { if(!c[g2[x][i]])
   	   dfs2(g2[x][i]);
   }	
 }
 

int dfs3(int x)
 { vis2[x]=1;
    int sum= num[x];
   for(int i=0;i<g[x].size();++i)
   { if(!vis2[g[x][i]])
   	     sum=sum+dfs3(g[x][i]); 
   }
 	return sum;
 }
 
 void kosaraju()
 {
 	dcnt=0;scnt=0;
 	memset(c,0,sizeof(c));
 	memset(vis,0,sizeof(vis));
 	for(int i=0;i<n;i++)
 	if(!vis[i])
 	dfs1(i);
 	for(int i=n-1;i>=0;i--)
 	if(!c[dfn[i]])
 	{
 		++scnt;
 		dfs2(dfn[i]);
	 }
 }
 
 void spoint()
 { 
	
    for(int i=0;i<n;i++)
    {indeg[i]=0;
	 g[i].clear();
	}
	for(int i=0;i<n;i++)
	{
	  num[c[i]]++;
	 for(int j=0;j<g1[i].size();j++)
	 { int v=g1[i][j];
	   if(c[i]!=c[v])
	   {g[c[v]].push_back(c[i]);
	    indeg[c[i]]++;
	   }
	 	
	 }
	}
	
 }
 

int main(int argc, char** argv) {
   int t,u,v;
    scanf("%d",&t);
   
   for(int i=1;i<=t;i++)
   {
      scanf("%d%d",&n,&m);
     for(int j=0;j<n;j++)
     {g1[j].clear();
      g2[j].clear();
      sum[j]=0;
      num[j]=0;
	 }
   	 for(int j=0;j<m;j++)
   	 { scanf("%d%d",&u,&v);
   	   
   	 	add1(u,v);
		}
			
   	kosaraju();
   	//cout<<"?";
   	spoint();
    
   	int maxn=-1;
   	for(int k=1;k<=scnt;++k)
   	{   
	   if(indeg[k]==0)
   	  {  for(int kk=0;kk<n;kk++)
   	     vis2[kk]=0;
		 sum[k]=dfs3(k);
   	     maxn=max(sum[k],maxn);
		 }
   	  
	   }
	   printf("Case %d: %d\n",i,maxn-1);
	   int f=0;
	   //cout<<"?"<<maxn[c[3]];
	   for(int k=0;k<n;k++)
	   {  if(sum[c[k]]==maxn)
	     { if(f==1)
		   printf(" %d",k); 
	       	else
	       	{printf("%d",k); 
	       	 f=1;
			   }
		 }
	   }
   	
   	 cout<<endl;
   }

	return 0;
}
发布了9 篇原创文章 · 获赞 0 · 访问量 108

猜你喜欢

转载自blog.csdn.net/qq_45224092/article/details/105574150