1. 程式人生 > >SUST_2018 焦作站亞洲區域賽校內選拔賽題解

SUST_2018 焦作站亞洲區域賽校內選拔賽題解

tag:圖論、最短路

//最短路
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 0x3f3f3f3f;
const int maxn = 1e5+7;
int t,n,m,cnt;
int dis[maxn];  //當前該點到原點最短距離
bool vis[maxn]; //是否訪問過
int head[maxn]; //點集
struct EDGE{
    int next,to,w,l,r;  //上一條邊,下一個點,權值,左值,右值
}edge[2*maxn];  //邊集
struct
NODE{ int u,dis; NODE(){} NODE(int u,ll w):u(u),dis(w){} bool operator <(const NODE &a)const{ return dis>a.dis; } }node[2*maxn]; //點集加最短距離 void add(int u, int v, int w, int l,int r){ //構建邊集 edge[cnt].next = head[u]; edge[cnt].to = v; edge[cnt].w = w; edge[cnt].l =
l; edge[cnt].r = r; head[u] = cnt; cnt++; } void init(){ //初始化 cnt = 0; memset(head,-1,sizeof(head)); memset(dis,maxx,sizeof(dis)); memset(vis,false,sizeof(vis)); } void read(){ //讀入資料 int u,v,w,l,r; scanf("%d%d",&n,&m); for(int i = 0;i < m; i++){ scanf
("%d%d%d%d%d",&u,&v,&w,&l,&r); add(u,v,w,l,r); add(v,u,w,l,r); } } void init_data(int kk){ //初始化資料 vis[kk] = false; dis[kk] = maxx; } int solve(int s){ priority_queue<NODE>q; //儲存最短距離 q.push(NODE(s,0)); //讀入原點 while(!q.empty()){ //佇列為空則無法到達 int kk = q.top().u; //儲存當前最短距離下標 int minD = q.top().dis; //儲存當前最短距離 q.pop(); if(kk==n) //若下標為目標值,return return minD; vis[kk] = true; //該點是否訪問 for(int l = head[kk]; l!=-1; l=edge[l].next){ //鬆弛邊 if(!vis[edge[l].to]&&minD<=edge[l].r&&minD>=edge[l].l&&minD + edge[l].w < dis[edge[l].to]){ dis[edge[l].to] = minD + edge[l].w; q.push(NODE(edge[l].to,dis[edge[l].to])); //將鬆弛後的邊壓入佇列 } } init_data(kk); //初始化資料 } return 0; } int main(){ scanf("%d",&t); while(t--){ init(); //初始化 r

tag:計算幾何、最短路

本題可以看出是計算幾何 + 最短路問題,最重要的只是對圖進行建模。 所以我們考慮在圖上摳出特殊點,來跑最短路。 特殊點包括牆的兩端之類的。

#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#define N 1010
#define inf 999999999.0
using namespace std;
 
struct data
{
    double x;
    double y[4];
}dt[10];
bool cmpx(data a,data b)
{
    return a.x<b.x;
}
struct point{
	double x,y;
	int id;
};
struct line{
	point d,u;
	int th;
};
int n,pnum,pline;
vector<line> vec;
vector<point> p;
double mp[N][N];
void add_line(point a,point b)
{
	line it;
	it.d=a;
	it.u=b;
	it.th=pline++;
	vec.push_back(it);
}
//叉積
double multi(point p0,point p1,point p2)
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
//判斷兩條線段是否相交
bool is_inter(point s1,point e1,point s2,point e2)
{
	return
	(max(s1.x,e1.x)>=min(s2.x,e2.x))&&
	(max(s2.x,e2.x)>=min(s1.x,e1.x))&&
	(max(s1.y,e1.y)>=min(s2.y,e2.y))&&
	(max(s2.y,e2.y)>=min(s1.y,e1.y))&&
	(multi(s1,s2,e1)*multi(s1,e1,e2)>0)&&
	(multi(s2,s1,e2)*multi(s2,e2,e1)>0);
 }
double dist(point a,point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 }
//建圖
void init()
{
	for(int i=0;i<=pnum;i++){
		for(int j=0;j<=pnum;j++){
			if(i==j){
				mp[i][j]=0.0;
				continue;
			}
			bool flag=1;
			point s1=p[i],e1=p[j];
			int l=(i+1)/2,r=(j+1)/2;
			for(int k=l+1;k<r;k++){
				if(is_inter(s1,e1,vec[k].d,vec[k].u)){
					flag=0;
					break;
				}
			}
			if(flag) mp[i][j]=mp[i][j]=dist(s1,e1);
			else mp[i][j]=mp[i][j]=inf;
		}
	}
 }
bool vis[N];
int pre[N];
double d[N];
void Dijkstra(int begin)
{
	for(int i=0;i<=pnum;i++){
		d[i]=inf;
		vis[i]=false;
	}
	d[begin]=0;
 
	for(int j=0;j<=pnum;j++){
		int k=-1,MIN=inf;
		for(int i=0;i<=pnum;i++)
		if(!vis[i]&&d[i]<MIN){
			MIN=d[i];
			k=i;
		}
		if(k==-1)	break;
		vis[k]=1;
		for(int i=0;i<=pnum;i++)
		if(!vis[i]&&d[i]<MIN){
			MIN=d[i];
			k=i;
		}
		if(k==-1)	break;
		vis[k]=1;
		for(int i=0;i<=pnum;i++)
		if(!vis[i]&&d[k]+mp[k][i]<d[i]){
			d[i]=d[k]+mp[k][i];
		}
	}
}
int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.out","w",stdout);
	while(scanf("%d",&n)!=EOF&&n!=-1){
		vec.clear();
		p.clear();
 
		double x,y1,y2,y3,y4;
		pnum=0;pline=0;
		point a,b;
		a.x=0,a.y=5.0,a.id=pnum++;
		p.push_back(a);
 
		for(int i=0;i<n;i++){
            scanf("%lf",&dt[i].x);
            for(int j=0;j<4;j++)
                scanf("%lf",&dt[i].y[j]);
            sort(dt[i].y,dt[i].y+4);
		}
		sort(dt,dt+n,cmpx);
 
/*
		for(int i=0;i<n;i++){
            printf("%.0lf\n",dt[i].x);
            for(int j=0;j<4;j++)
                printf("%.0lf ",dt[i].y[j]);
                printf("\n");
		}
*/
        for(int i=0;i<n;i++){
            a.x=dt[i].x;
            b.x=dt[i].x;
 
             a.y=0.0;
             b.y=dt[i].y[0];
             a.id=pnum++;
             b.id=pnum++;
             add_line(a,b);
             p.push_back(a);
             p.push_back(b);
 
             a.y=dt[i].y[1];
             b.y=dt[i].y[2];
             a.id=pnum++;
             b.id=pnum++;
             add_line(a,b);
             p.push_back(a);
             p.push_back(b);
 
             a.y=dt[i].y[3];
             b.y=10.0;
             a.id=pnum++;
             b.id=pnum++;
             add_line(a,b);
             p.push_back(a);
             p.push_back(b);
        }
		a.x=10.0;a.y=5.0;a.id=pnum;
		p.push_back(a);
		init();
		Dijkstra(0);
		printf("%.2f\n",d[pnum]);
	}
	return 0;
}

tag:圖論、生成樹

//次小生成樹
#include<bits/stdc++.h>
using namespace std;
const int L=1e5+7;
const int inf=0x3f3f3f3f;
const int maxn=1000+7;
int father[maxn],n,m,num[maxn],nPos;    //父節點(並查集),點數,邊數,最小生成樹點集,當前訪問方位
struct node{
    int s,y,w;
}edge[L];   //邊集,左端點,右端點,權值
void init(){    //初始化並查集
    for(int i=0;i<=n;i++)
        father[i]=i;
}
int root(int x){    //並查集,構造父節點
    return father[x]==x?x:father[x]=root(father[x]);
}
void unite(int x,int y){    //並查集,合併兩個聯通圖
    x=root(x);
    y=root(y);
    if(x!=y)
        father[y]=x;
}
int alike(int x,int y){ //並查集,判斷是否為同一連通圖
    return root(x)==root(y);
}
int cmp(node a,node b){ //sort結構體排序
    return a.w<b.w;
}
int secondTree(int pos) //次小生成樹
{
    init(); //初始化
    int sum=0,cnt=0;
    for(int i=0;i<m;i++)    //對於刪去邊後的圖進行最小生成樹運算
    {
        if(cnt==n-1