Tävlingsprogrammering/Uppgifter/Järnvägen

Från Wikibooks
Hoppa till navigering Hoppa till sök


Järnvägen

I dessa tider av avreglerad järnväg bestämmer sig Loke för att starta ett eget tågföretag som ska trafikera en viss järnvägslinje. Längs denna järnväg finns flera stationer och ett av Lokes första projekt är att bestämma vid vilka stationer det viktiga morgontåget ska stanna. Loke vill grunda sitt beslut på en stor enkätundersökning där han frågat varje tänkbar resenär mellan vilka stationer de vill åka och hur lång restid de kan tänka sig innan de väljer något annat färdsätt. Skriv ett program som utifrån detta underlag bestämmer vilka stationer tåget ska stanna vid för att det totala antalet personkilometer ska bli så stort som möjligt.

Järnvägen i exemplet. Pilarna visar personernas önskade ressträckor. Beroende på vilken maximal restid E väljer så blir olika mellanstationer optimala. I exempel 1 åker A, B, C och D med tåget. I exempel 2 åker B och E. I exempel 3 åker A, D och E. I exempel 4 åker A, B, D och E.

Indata

På första raden står två heltal 3≤N ≤20, antalet stationer, och 1≤P≤100, antalet tillfrågade personer. Stationerna är numrerade i ordning längs spåret från startstationen 1 till slutstationen N (vid dessa två stationer måste tåget givetvis stanna). Därefter följer en rad med N−1 heltal i intervallet 2 till 1000, längden i kilometer på varje delsträcka mellan stationerna (se figur). Samtliga dessa tal är för enkelhets skull jämnt delbara med två. Tåget går nämligen normalt alltid med 120 km/h hastighet, d.v.s. varje kilometer tar exakt en halv minut. Inbromsning och acceleration gör dock att tiden för varje delsträcka förlängs med en minut om tåget stannar vid en av stationerna i delsträckans ändpunkter och två minuter om det stannar vid båda stationerna. Ingen extra tid behöver räknas för in- och avlastning, utan ankomsttid och avgångstid är samma. Slutligen följer P rader med enkätsvaren, där varje rad innehåller svaren från en person: tre heltal A, B och M, där A är stationen personen vill åka från, B är stationen personen vill åka till och M är den maximala restiden (i minuter) han eller hon kan tänka sig. Talen uppfyller 1≤A<B≤N, samt 2≤M≤1000.

Delpoäng: För 30% av poängen gäller att N≤10.

Utdata

Första raden ska innehålla det maximala antalet personkilometer som kan tillryggaläggas, d.v.s. för varje passagerare som får sina krav tillgodosedda summerar man sträckan som hon eller han reser. Sedan ska programmet skriva ut tidtabellen som åstadkommer detta maximala antal personkilometer. Den består av en rad med två tal för varje station som tåget stannar vid: stationens nummer samt tidpunkten då tåget stannar där. Tåget startar alltid vid tiden 0. Om det finns flera möjliga tidtabeller ska programmet välja en som är framme vid slutstationen så tidigt som möjligt.

Exempel 1

Exempel 1: Indata Exempel 1: Utdata
8 5
20 42 30 18 14 8 42
3 4 21
6 8 29
3 5 30
3 4 25
2 7 59
158
1 0
3 33
4 50
5 61
6 70
8 97
Exempel 2: Indata Exempel 3: Utdata
8 5
20 42 30 18 14 8 42
3 4 21
6 8 29
3 5 30
3 4 25
2 7 60
162
1 0
2 12
6 66
7 72
8 95
Exempel 3: Indata Exempel 3: Utdata
8 5
20 42 30 18 14 8 42
3 4 21
6 8 29
3 5 30
3 4 25
2 7 62
172
1 0
2 12
3 35
4 52
7 74
8 97
Exempel 4: Indata Exempel 4: Indata
8 5
20 42 30 18 14 8 42
3 4 21
6 8 29
3 5 30
3 4 25
2 7 65
222
1 0
2 12
3 35
4 52
6 70
7 76
8 99

Lösning[redigera]

Eftersom N ≤20 finns det högst 18 varierbara stationer, d.v.s. högst 2^18=262144 möjliga alternativ hur tåget kan stanna. Vi hinner därför gå igenom alla alternativ. För varje alternativ räknar vi ut tågets tidtabell, jämför denna med varje persons krav och summerar antalet personkilometer som alternativet innebär. Om antalet personkilometer är större än det hittills största hittade, eller om antalet personkilometer är lika stort men tåget är framme tidigare, så sparar vi det alternativet som det bästa hittills.

För att generera alla alternativ kan man använda sig av ett smidigt trick, nämligen att varje alternativ motsvarar den binära representationen av ett tal mellan 0 och 2^(N-2)-1, där varje binär siffra anger om tåget stannar på en viss station (1) eller inte (0). Exempelvis, om N=5 så att det finns 3 varierbara stationer, så motsvarar binärtalet "001" att tåget stannar på station 4 men inte på station 2 och 3, medan binärtalet "111" motsvarar att tåget stannar på alla stationerna. För att "plocka ut" en viss sffra ur ett tal kan man .tex. använda bitvisa operatorer.

Lösning i C:

#include <stdio.h>

int main() {
  int N,P,s[30],st[30],t[30],cs[30],bra[30],a[100],b[100],mx[100],max,tot,i,j;
  scanf("%d %d",&N,&P);
  for(i=0;i<N-1;i++) scanf("%d", &s[i]);
  cs[0]=0;
  for(j=1;j<N;j++) cs[j]=cs[j-1]+s[j-1];
  for(i=0;i<P;i++) {scanf("%d %d %d", &a[i],&b[i],&mx[i]); a[i]--; b[i]--; }
  max=0;
  for(i=0;i<(1<<(N-2));i++) {
    for(j=0;j<N-2;j++) st[j+1]=(i>>j)&1;
    st[0]=st[N-1]=1;
    t[0]=0;
   for(j=1;j<N;j++) t[j]=t[j-1]+s[j-1]/2+st[j-1]+st[j];
   tot=0;
   for(j=0;j<P;j++) if(st[a[j]] && st[b[j]] && t[b[j]]-t[a[j]]<=mx[j]) tot+=cs[b[j]]-cs[a[j]];
   if(tot>max || (tot==max && t[N-1]>bra[N-1])) {
     max=tot;
     for(j=0;j<N;j++) bra[j]=st[j]?t[j]:-1;
    }
  }
  printf("%d\n", max);
  for(i=0;i<N;i++) if(bra[i]>=0) printf("%d %d\n", i+1,bra[i]);
  return 0;
 }