SUST_2018 焦作站亞洲區域賽校內選拔賽題解
阿新 • • 發佈:2018-12-12
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