一起开心2020暑假训练第二周 图论(模板题)

比赛链接:

A HDU 1285 一

拓扑排序模板题,记录每个点的入度,然后按照入度大小以及顺序进行输出

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
bool map[517][517];
int in[517];
priority_queue<int,vector<int>,greater<int> > q;
void topo(int n)
{
    for(int i=1;i<=n;i++)
    {
        if(in[i]==0)
            q.push(i);
    }
    int c=1;
    while(!q.empty())
    {
        int v=q.top();
        q.pop();
        if(c!=n)
        {
            cout<<v<<" ";
            c++;
        }
        else
            cout<<v<<endl;
        for(int i=1;i<=n;i++)
        {
            if(!map[v][i])
                continue;
            in[i]--;
            if(!in[i])
                q.push(i);
 
        }
    }
}
int main()
{
    int n,m,i,j;
    while(cin>>n>>m)
    {
        int k=0;
        memset(map,0,sizeof map);
        memset(in,0,sizeof in);
        while(m--)
        {
            cin>>i>>j;
            if(map[i][j])
                continue;
            map[i][j]=1;
            in[j]++;
        }
        topo(n);
    }
}

B HDU 1863 起

最小生成树模板题

#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=1e6+32;
struct node{
	int u,v,w;
}edge[maxn];
int fa[maxn];
int total=0;
bool cmp(node x,node y)
{
	return x.w<y.w;
}
int sum=0;
int find(int x)
{
	if(fa[x]==x)return x;
	else return find(fa[x]);
}
inline void Kruskal()
{
	total=0;
	sum=0;
	for(int i=1;i<=m;i++)
	{
		int u=find(edge[i].u);
		int v=find(edge[i].v);
		if(u==v)continue;
		sum+=edge[i].w;
		fa[u]=v;
		total++;
		if(total==n-1)break;
	}
 } 
int main()
{
	while(cin>>m>>n)
	{
		if(m==0)break;
		for(int i=1;i<=n;i++)fa[i]=i;
		memset(edge,0,sizeof(edge));
		for(int i=1;i<=m;i++)
		{
			cin>>edge[i].u>>edge[i].v>>edge[i].w;
		}
		sort(edge+1,edge+1+m,cmp);
		Kruskal();
		if(total==n-1)cout<<sum<<endl;
		else cout<<"?"<<endl;
	}

	return 0;
}

C POJ 2387 开

最短路模板,从n 到 1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
const long long inf=2147483647;
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,num_edge=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
  int next,to,dis;
}edge[maxm]; //结构体表示静态邻接表
void addedge(int from,int to,int dis) //邻接表建图
{ //以下是数据结构书上的标准代码,不懂翻书看解释
  edge[++num_edge].next=head[from]; //链式存储下一条出边
  edge[num_edge].to=to; //当前节点编号
  edge[num_edge].dis=dis; //本条边的距离
  head[from]=num_edge; //记录下一次的出边情况
}
void spfa()
{
  queue<int> q; //spfa用队列,这里用了STL的标准队列
  for(int i=1; i<=n; i++) 
  {
    dis[i]=inf; //带权图初始化
    vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
  }
  q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
  while(!q.empty())
  {
    int u=q.front(); //取出队首
    q.pop(); vis[u]=0; //出队标记
    for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
    {
      int v=edge[i].to; 
      if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
      {
        dis[v]=dis[u]+edge[i].dis;
        if(vis[v]==0) //未入队则入队
        {
          vis[v]=1; //标记入队
          q.push(v);
        }
      }
    }
  }
}
int main()
{
  cin>>m>>n;
  s=n;
  for(int i=1; i<=m; i++)
  {
    int f,g,w;
    cin>>f>>g>>w; 
    addedge(f,g,w); //建图,有向图连一次边就可以了
    addedge(g,f,w);
  }
   spfa(); //开始跑spfa
	cout<<dis[1]<<endl; //否则打印最短距离
  return 0;
}

D POJ 1502 心

也是最短路模板题,只是读入方式有些奇怪

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>

#define inf 0x7f
using namespace std;
const int MAXN=10010,MAXM=500010;

struct XY{
	int w,to,pre;
}e[MAXM];
 
struct XX{
	int dis,num;
}d[MAXN],tmp;
 
struct cmp1{
	bool operator ()(XX &a,XX &b){
		return a.dis>b.dis;
	}
};
char w[110];
int n,s,sz=0;
int las[100010];
bool flag[MAXN];
priority_queue<XX,vector<XX>,cmp1> q;
 
void init()
{
	sz=0;
	memset(las,0,sizeof(las));
	memset(flag,0,sizeof(flag));
}
void add(int x,int y,int w){
	++sz;
	e[sz].to=y;
	e[sz].w=w;
	e[sz].pre=las[x];
	las[x]=sz;
}
 
 
void Dijkstra(){
	int min,u=0;
	s=1;
	d[s].dis=0;
	q.push(d[s]);
	while (!q.empty()){
		u=q.top().num;
		q.pop();
		if (flag[u]) continue;
		flag[u]=true;
		for (int j=las[u];j;j=e[j].pre){
			int mu=e[j].to;
			if (d[mu].dis>d[u].dis+e[j].w){
				d[mu].dis=d[u].dis+e[j].w;
				q.push(d[mu]);
			}
		}
	}
}

int zhuanhua(char s[])
{
    if(s[0]=='x')
        return inf;
    else
    {
        int sum=0;
        for(int i=0; i<strlen(s); i++)
            sum=sum*10+s[i]-'0';
        return sum;
    }
}


int main(){
	while(scanf("%d",&n)!=EOF)
	{
		init();
		memset(e,0,sizeof(e));
		for (int i=1;i<=n;++i)
		{
			d[i].num=i;
			d[i].dis=2147483647;
		}
		for(int i=2;i<=n;i++)
		{
			for(int j=1;j<i;j++)
			{
				scanf("%s",w);
				int zz=zhuanhua(w);
				add(i,j,zz);
			    add(j,i,zz);
			}
		}
		
		Dijkstra();
		int maxx=0;
		for (int i=1;i<=n;++i)
			maxx=max(maxx,d[i].dis);
		cout <<maxx;
		while(!q.empty())q.pop(); 
	}

	return 0;
}

E HDU 5922 图

找规律,表面是最小生成树,但仔细看会发现将点1与其他点相连费用最低(因为费用为两点之和,而1是最小的数)

#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
	int t;
	cin>>t;
	for(int i=1;i<=t;i++)
	{
		ll n;
		cin>>n;
		
		printf("Case #%d: %lld\n",i,(n-1)*(n+2)/2);
	}
}

F HDU 2112 论

也是最短路,不过每个站点都是具体的城市名,可以用map实现名字与编号的唯一对应

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<queue>
const long long inf=2147483647;
const int maxn=30005;
const int maxm=70005;
using namespace std;
int n,m,s,num_edge=0;
map<string,int>mp; 
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
  int next,to,dis;
}edge[maxm]; //结构体表示静态邻接表
void addedge(int from,int to,int dis) //邻接表建图
{ //以下是数据结构书上的标准代码,不懂翻书看解释
  edge[++num_edge].next=head[from]; //链式存储下一条出边
  edge[num_edge].to=to; //当前节点编号
  edge[num_edge].dis=dis; //本条边的距离
  head[from]=num_edge; //记录下一次的出边情况
}
void spfa()
{
  queue<int> q; //spfa用队列,这里用了STL的标准队列
  for(int i=1; i<=n; i++) 
  {
    dis[i]=inf; //带权图初始化
    vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
  }
  q.push(s); 
  dis[s]=0;
vis[s]=1; //第一个顶点入队,进行标记
  while(!q.empty())
  {
    int u=q.front(); //取出队首
    q.pop(); vis[u]=0; //出队标记
    for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
    {
      int v=edge[i].to; 
      if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
      {
        dis[v]=dis[u]+edge[i].dis;
        if(vis[v]==0) //未入队则入队
        {
          vis[v]=1; //标记入队
          q.push(v);
        }
      }
    }
  }
}
void init()
{
	num_edge=0;
	mp.erase(mp.begin(),mp.end());
	memset(head,0,sizeof(head));
	memset(edge,0,sizeof(edge));
	
}
int main()
{
	while(cin>>m)
	{
		init();
		if(m==-1)break;
		string a,end,b;
		cin>>a>>end;
		mp[a]=1;
	  	s=1;
	  	int cnt=1;
	 	 for(int i=1; i<=m; i++)
	 	{
	 		int w;
	    cin>>a>>b>>w;
		if(mp[a]==0)
		mp[a]=++cnt;
		if(mp[b]==0)
		mp[b]=++cnt; 
	    addedge(mp[a],mp[b],w); //建图,有向图连一次边就可以了
	    addedge(mp[b],mp[a],w);
	  	}
	  	n=cnt;
	   spfa(); //开始跑spfa
	   if(mp[end]==0||dis[mp[end]]==inf)
		cout<<"-1"<<endl;
	  else cout<<dis[mp[end]]<<endl; //否则打印最短距离
	}

  return 0;
}
posted @ 2020-07-13 16:31  回归梦想  阅读(110)  评论(0编辑  收藏  举报