您的位置:首页 > Web前端

USACO Fence Loops 解题报告

2014-01-08 05:26 316 查看
这道题是看了网上的思路做出来的。之前尝试过(最小)生成树的方法,这似乎是获取所有“基本环”的标准方法,时间复杂度也更低,但由于我不知道怎么证明加之懒惰,没有这样实现。

这道题的思路是:逐一去掉一条边(把这条边的length设为无穷大),然后求从这条边的左端点到右端点的最短路径(使用Dijkstra),这样通过该边的最小基本环的长度就是这条边的长度与最短路径之和。所有的边遍历完后,最小基本环中最小的即为所求。由于对每条边都要运行一次Dijkstra,所以时间复杂度为O(E^2logV). 结题报告中有优化方法,大意似乎是去掉长于当前最小基本环的环。不过也懒得细看了。。。

这道题值得总结的地方是Dijkstra的实现。之前也实现过,不过确实感到很复杂,heap的操作都要自己写一遍。这里附上标准结题报告,算是Dijkstra标准程序吧。我自己的实现为了简单,使用了map,时间复杂度变成了EV。

/*
ID: thestor1
LANG: C++
TASK: fence6
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <climits>
#include <cassert>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>

using namespace std;

const int INF = 30000;

bool cmp(const pair<int, int> &lhs, const pair<int, int> &rhs)
{
return lhs.second > rhs.second;
}

int dijkstra(int s, const int N, vector<int> &length, const vector<set<int> > &ladj, const vector<set<int> > &radj)
{
int ls = length[s];
length[s] = INF;

map<int, int> dis;
for(int i = 0; i < N; ++i)
{
dis[i] = INF;
}

for(set<int>::iterator iter = ladj[s].begin(); iter != ladj[s].end(); ++iter)
{
dis[*iter] = length[*iter];
}

while(dis.size())
{
// cout<<"dis:";
// for(map<int, int>::iterator iter = dis.begin(); iter != dis.end(); ++iter)
// {
// 	cout<<iter->first<<", "<<iter->second<<"\t";
// }
// cout<<endl;

map<int, int>::iterator uiter = dis.begin();
for(map<int, int>::iterator iter = ++dis.begin(); iter != dis.end(); ++iter)
{
if(iter->second < uiter->second)
{
uiter = iter;
}
}

int u = uiter->first, du = uiter->second;
// cout<<"u:"<<u<<", du:"<<du<<endl;
// int size = dis.size();
dis.erase(uiter);
// assert(dis.size() == size - 1);

if(radj[s].find(u) != radj[s].end() || du == INF)
{
length[s] = ls;
return du;
}

for(map<int, int>::iterator iter = dis.begin(); iter != dis.end(); ++iter)
{
if((ladj[u].find(iter->first) != ladj[u].end() || radj[u].find(iter->first) != radj[u].end()) && iter->second > du + length[iter->first])
{
iter->second = du + length[iter->first];
}
}
}
length[s] = ls;
return INF;
}

int main()
{
FILE *fin  = fopen("fence6.in", "r");
FILE *fout = fopen("fence6.out", "w");
int N;
fscanf(fin, "%d", &N);
// cout<<"N: "<<N<<endl;
vector<int> length(N);
vector<set<int> > ladj(N);
vector<set<int> > radj(N);
for(int i = 0; i < N; ++i)
{
int s, l, n1, n2;
fscanf(fin, "%d%d%d%d", &s, &l, &n1, &n2);
length[s - 1] = l;
for(int j = 0; j < n1; ++j)
{
int k;
fscanf(fin, "%d", &k);
ladj[s - 1].insert(k - 1);
}
for(int j = 0; j < n2; ++j)
{
int k;
fscanf(fin, "%d", &k);
radj[s - 1].insert(k - 1);
}
}

// cout<<"ladj[0]:";
// for(set<int>::iterator iter = ladj[0].begin(); iter != ladj[0].end(); ++iter)
// {
// 	cout<<*iter<<"\t";
// }
// cout<<endl;

// cout<<"radj[0]:";
// for(set<int>::iterator iter = radj[0].begin(); iter != radj[0].end(); ++iter)
// {
// 	cout<<*iter<<"\t";
// }
// cout<<endl;

int mincycle = -1, mini = -1;
for(int i = 0; i < N; ++i)
{
int thiscycle = length[i] + dijkstra(i, N, length, ladj, radj);
if(mincycle < 0 || thiscycle < mincycle)
{
mincycle = thiscycle;
mini = i;
}
}

// cout<<"[main]mincycle:"<<mincycle<<", mini:"<<mini<<", length[i]:"<<length[mini]<<", dijkstra:"<<dijkstra(mini, N, length, ladj, radj)<<endl;
fprintf(fout, "%d\n", mincycle);

fclose(fin);
fclose(fout);
return 0;
}


标准程序:

#include <stdio.h>

/* maximum number of segments */
#define MAXS 100

/* an edge is a fence segment */
/* a place is a side of a fence segment */
/* there are two places for each edge */

/* conn is the index of the incident edge */
/* alist is the index of the incident place */

int conn[2*MAXS][8]; /* one edge list for each side of each segment */
int ccnt[2*MAXS]; /* number of incident edges */
int length[MAXS]; /* length of the segments */

int alist[2*MAXS][8]; /* adjacency list for each end of each segment */

int nfence; /* numbor of fences */
int npl; /* number of places */

int dist[2*MAXS]; /* distance to each place */

/* heap data structure */
int heap[2*MAXS];
int hsize;
int hloc[2*MAXS]; /* location within heap of each place */

/* debugging routine */
/* ensure heap order has been maintained */
void check_heap(void)
{
int lv;

for (lv = 1; lv < hsize; lv++)
{
if (dist[heap[lv]] < dist[heap[(lv-1)/2]])
{
fprintf (stderr, "HEAP ERROR!\n");
return;
}
}
}

/* delete the minimum item from the heap */
void delete_min(void)
{
int loc, val;
int p, t;

/* remove last item in the heap array */
loc = heap[--hsize];
val = dist[loc];
p = 0;

while (2*p+1 < hsize)
{
/* find smaller child */
t = 2*p+1;
if (t+1 < hsize && dist[heap[t+1]] < dist[heap[t]]) t++;

/* if child less than the removed item, move child up */
if (dist[heap[t]] < val)
{
heap[p] = heap[t];
hloc[heap[p]] = p;
p = t;
} else break; /* otherwise, put removed item here */
}

/* put removed item back into the heap */
heap[p] = loc;
hloc[loc] = p;
check_heap(); /* sanity check */
}

void update(int loc)
{ /* we've decreased the value of dist[loc] */
/* change heap to maintain heap order */
int val;
int p, t;

val = dist[loc];
p = hloc[loc];
while (p > 0)
{ /* while the element's not the root of the heap */

/* check to see if it's less than it's parent */
t = (p-1)/2;
if (dist[heap[t]] > val)
{ /* if so, move parent down */
heap[p] = heap[t];
hloc[heap[p]] = p;

/* consider as if updated element is now in parent's prev location */
p = t;
} else break; /* otherwise, stop */
}

/* put element in proper location in heap */
heap[p] = loc;
hloc[loc] = p;
check_heap(); /* sanity check */
}

void add_heap(int loc)
{ /* add an element to the heap /*

if (hloc[loc] == -1)
{ /* if it's not in the heap, add to the end (eff value = infinity) */
heap[hsize++] = loc;
hloc[loc] = hsize-1;
}

/* change the value to the real value */
update(loc);
}

void fill_dist(int s)
{
int lv;
int p;
int t;
int l;

/* initialize hloc & dist */
for (lv = 0; lv < npl; lv++) { hloc[lv] = -1; dist[lv] = 255*MAXS + 1; }
dist[s] = 0;
hsize = 0;
add_heap(s);

while (hsize)
{ /* heap is not empty */

/* take minimum distance location */
p = heap[0];
delete_min();
t = dist[p];

/* try all possible endpoints of other edges at the same location */
for (lv = 0; lv < ccnt[p]; lv++)
{
l = alist[p][lv];
if (dist[l] > t)
{ /* found better distance */
dist[l] = t;
add_heap(l); /* add, if necessary, update otherwise */
}
}

/* consider moving across this edge */
t = dist[p] + length[p/2];
p = p ^ 0x1; /* go to the other endpoint */
if (dist[p] > t)
{ /* found a better way to get to the location */
dist[p] = t;
add_heap(p);
}
}
}

int main(int argc, char **argv)
{
FILE *fout, *fin;
int lv, lv2, lv3;
int c1, c2;
int segid, len;
int p;
int min;

if ((fin = fopen("fence6.in", "r")) == NULL)
{
perror ("fopen fin");
exit(1);
}
if ((fout = fopen("fence6.out", "w")) == NULL)
{
perror ("fopen fout");
exit(1);
}

fscanf (fin, "%d\n", &nfence);
npl = nfence*2;

for (lv = 0; lv < nfence; lv++)
{ /* read in edges */
fscanf (fin, "%d %d %d %d", &segid, &len, &c1, &c2);
segid--;
length[segid] = len;
ccnt[2*segid] = c1;
ccnt[2*segid+1] = c2;
while (c1--)
{
fscanf (fin, "%d", &p);
conn[2*segid][c1] = p-1;
}
while (c2--)
{
fscanf (fin, "%d", &p);
conn[2*segid+1][c2] = p-1;
}
}

for (lv = 0; lv < npl; lv++)
for (lv2 = 0; lv2 < ccnt[lv]; lv2++)
{ /* for all edges */
c1 = lv/2;
c2 = conn[lv][lv2]*2;

/* find other occurance of edge */
for (lv3 = 0; lv3 < ccnt[c2]; lv3++)
if (conn[c2][lv3] == c1)
break;

/* if no match was found, must be on 'other' side of edge */
if (lv3 >= ccnt[c2]) c2++;

/* update adjaceny list */
alist[lv][lv2] = c2;
}

min = 255*MAXS+1; /* higher than we could ever see */

for (lv = 0; lv < nfence; lv++)
{ /* for each fence */

/* make edge infinite length, to ensure it's not used */
len = length[lv];
length[lv] = 255*MAXS+1;

/* find distance from one end-point of edge to the other */
fill_dist(2*lv);

/* if the cycle (the path plus the edge deleted) is better
than the best found so far, update min */
if (dist[2*lv+1] + len < min)
min = dist[2*lv+1] + len;

/* put edge back in */
/* actually, not necessary, since we've already found the
best cycle which uses this edge */
length[lv] = len;
}

fprintf (fout, "%i\n", min);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: