Warning
This page is located in archive. Go to the latest version of this course pages.

Key Servers

Přehled

zadání

Kódy nejrychlejších řešení viz níže.

Relativní čas vůči referenčnímu řešení se počítá tak, že se sečtou v posledním odevzdaném studentském řešení všechny časy na neveřejných souborech ( časStud ), všechny časy na na neveřejných souborech v referenčním řešení ( časRef ) a spočte se podíl časStud/časRef. Zveřejňujeme pouze časy řešitelů, kteří dosáhli na 10/10. Časy řešení v některých instancích pomalých nebo chybných pravděpodobně nejsou směrodatné.

řešitel     jazyk      relativní čas vůči referenčnímu řešení 
 
skalaja7     Cpp | 10  0.145 
preister       C | 10  0.168 
krivapa2       C | 10  0.174 
klimema4       C | 10  0.179 
lebeddar       C | 10  0.197 
konicsim       C | 10  0.201 
mertahan       C | 10  0.205 
nollhyne       C | 10  0.212 
novotvo8       C | 10  0.220 
pultami1     Cpp | 10  0.223 
krouppe2       C | 10  0.228 
neckavit     Cpp | 10  0.249 
dedkoba1     Cpp | 10  0.250 
kacenjir       C | 10  0.252 
jakeskla       C | 10  0.270 
skoreja5       C | 10  0.270 
brejcka1     Cpp | 10  0.285 
voracva1     Cpp | 10  0.288 
hrubype7     Cpp | 10  0.296 
glingvla       C | 10  0.325 
nejtejan     Cpp | 10  0.334 
jakouto3     Cpp | 10  0.339 
klanjan      Cpp | 10  0.341 
brezipat     Cpp | 10  0.348 
filomich     Cpp | 10  0.353 
sustemar     Cpp | 10  0.356 
repamart       C | 10  0.361 
stoklji1     Cpp | 10  0.368 
manousim     Cpp | 10  0.378 
hvezdmic     Cpp | 10  0.398 
janatpa3     Cpp | 10  0.406 
cernypro     Cpp | 10  0.413 
buitiepq     Cpp | 10  0.580 
ivashmak     Cpp | 10  0.648 
svehlja7    Java | 10  0.854 
trnkavla    Java | 10  0.873 
jirmaja1    Java | 10  1.144 
filipcsa    Java | 10  1.270 
turynmar    Java | 10  1.456 
ottastep    Java | 10  1.466 

1. nejrychlejší v C/C++

#include <vector>
#include <cstdio>
#include <stack>
#include <cstdlib>
 
#ifdef WIN32
 
int getchar_unlocked() { return getchar(); }
 
#elif UNIX
/* Do linux stuff */
#endif
 
using namespace std;
 
struct edge;
 
typedef struct node {
    int id;
    vector<edge> connections;
    bool server = false;
    bool server_origin = false;
    bool deleted = false;
    bool start = false;
    int virtual_size = 0;
} node_t;
 
typedef struct edge {
    node_t *from;
    node_t *to;
    int cost;
 
    bool deleted() {
        return to->deleted || from->deleted;
    }
} edge_t;
 
static inline void scanint(int &x) {
    // fastest stdin reading, found on https://stackoverflow.com/questions/27899413/understanding-getchar-unlocked
    register int c = getchar_unlocked();
    x = 0;
    for (; (c < 48 || c > 57); c = getchar_unlocked());
    for (; c > 47 && c < 58; c = getchar_unlocked()) {
        x = (x << 1) + (x << 3) + (c & 15);
    }
}
 
int main() {
    int edges_count, servers_count;
    scanf("%d %d", &edges_count, &servers_count);
 
    vector<node_t *> nodes(static_cast<unsigned int>(edges_count));
    vector<node_t *> circle_nodes;
 
    unsigned int total_cost = 0;
    unsigned int confirmed_cost = 0; // cena jen pro originální servery
 
    bool created[edges_count] = {false};
 
    for (int i = 0; i < edges_count; ++i) {
        int from, to, cost;
        scanint(from);
        scanint(to);
        scanint(cost);
 
        if (!created[from]) {
            nodes[from] = new node_t();
            created[from] = true;
        }
 
        if (!created[to]) {
            nodes[to] = new node_t();
            created[to] = true;
        }
 
        edge_t e1, e2;
        e1.to = nodes[to];
        e1.from = nodes[from];
 
        e2.to = nodes[from];
        e2.from = nodes[to];
 
        e2.cost = e1.cost = cost;
        nodes[from]->connections.push_back(e1);
        nodes[from]->virtual_size++;
 
        nodes[from]->id = from;
        nodes[to]->connections.push_back(e2);
        nodes[to]->virtual_size++;
 
        nodes[to]->id = to;
    }
 
    int server_ids[servers_count] = {0};
    node_t *start;
 
    // přidání serverů a startu
    for (int i = 0; i < servers_count; ++i) {
        int id;
        scanint(id);
        nodes[id]->server = true;
        nodes[id]->server_origin = true;
        server_ids[i] = id;
 
        if (i == 0) {
            nodes[id]->start = true;
            start = nodes[id];
        }
    }
 
    stack<node_t *> leaves;
 
    // přidání listů do stacku
    for (int i = 0; i < nodes.size(); ++i) {
        if (!nodes[i]->deleted && nodes[i]->connections.size() == 1) {
            leaves.push(nodes[i]);
        }
 
        while (!leaves.empty()) {
            node_t *current = leaves.top();
            leaves.pop();
 
            if (current->server_origin) {
                confirmed_cost = total_cost;
            }
 
            node_t *next;
            int x;
 
            // smaž zakázané hrany
            for (x = 0; x < current->connections.size(); ++x) {
                if (!current->connections[x].deleted()) {
                    next = current->connections[x].to;
                    break;
                }
            }
 
            // pokud jdu ze serveru
            if (current->server) {
                next->server = true;
                total_cost += 2 * current->connections[x].cost; // tam a zpět
            }
 
            if (current->start) {
                next->start = true;
            }
 
            current->deleted = true;
            next->virtual_size--;
            if (next->virtual_size == 1)
                leaves.push(next);
        }
    }
 
 
 
    // Zjistit jestli není kružnice reundandní
    int found = 0;
    for (int i = 0; i < nodes.size(); ++i) {
        if (nodes[i]->deleted) continue;
        if (nodes[i]->server) {
            start = nodes[i];
            found++;
        }
    }
 
    if (found == 1) {
        // kružnice je nepotřebná
        printf("%d\n", confirmed_cost);
        exit(0);
    }
 
 
    int biggestCostBetweenservers = 0;
    int circleCost = 0;
    int temporaryEdgeCost = 0;
 
    int iterationCounter = 0;
    node_t *current = start;
 
    while (true) {
        ++iterationCounter;
        if (current == start && iterationCounter > 1) {
            if (temporaryEdgeCost > biggestCostBetweenservers) {
                biggestCostBetweenservers = temporaryEdgeCost;
            }
            goto konec;
        }
 
        if (current->server && temporaryEdgeCost > biggestCostBetweenservers) {
            biggestCostBetweenservers = temporaryEdgeCost;
            temporaryEdgeCost = 0;
        } else if (current->server)
            temporaryEdgeCost = 0;
 
 
        for (int i = 0; i < current->connections.size(); ++i) {
            if (iterationCounter > 2 && current->connections[i].to == start) {
                circleCost += current->connections[i].cost;
                temporaryEdgeCost += current->connections[i].cost;
                current->deleted = true;
                current = current->connections[i].to;
                goto dalsiIerace;
            }
 
            if (!current->connections[i].deleted()) {
                circleCost = circleCost + current->connections[i].cost;
                temporaryEdgeCost = temporaryEdgeCost + current->connections[i].cost;
                current->deleted = true;
                current = current->connections[i].to;
                goto dalsiIerace;
            }
        }
 
        dalsiIerace:;
    }
 
    konec:
    int n = 2 * (circleCost - biggestCostBetweenservers);
    printf("%d\n", (n < circleCost ? 2 * (circleCost - biggestCostBetweenservers) : circleCost) + total_cost);
    return 0;
}

2. nejrychlejší v C/C++

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
 
//ZKOUSIM ZAPOCITAT MEZERU
int all_servers;
unsigned char *used;
unsigned char *done_socket;
unsigned char *visited;
unsigned char *help_visited;
unsigned char *side;
unsigned char *zapocitat;
int *queue;
int *neighbour_counter;
int *opposite_neigh;
unsigned char * keys;
 
int bfs_count = 0;
int done = 0;
int rear = 0;
 
struct node {
    int value;
    int price;
    int edge_number;
    struct node* next;
};
 
struct Graph {
    struct node** adjLists;
    int numElements;
};
 
struct node* createNode(int vertex, int price, int edge_number) {
    struct node* newNode = malloc(sizeof(struct node));
    newNode->next = NULL;
    newNode->value = vertex; //do struktury node mam podle me pridat hranu a tady to pak musim inicializovat
    newNode->price = price;
    newNode->edge_number = edge_number;
    return newNode;
}
 
  void printmatrixchar(int rows, unsigned char* arr){
    for(int i =0; i<rows;i++){
        printf("%i ",arr[i]);
    }
    printf("\n");
}
 void printmatrixint(int rows, int* arr){
    for(int i =0; i<rows;i++){
        printf("%i ",arr[i]);
    }
    printf("\n");
}
 
 
//pridani hran 
void addEdge(struct Graph* graph, int src, int dest, int val, int edge) {
    //pridavam hranu z prvniho prvku do druheho
    struct node* newNode = createNode(dest, val, edge);
    newNode->next = graph->adjLists[src];
    graph->adjLists[src] = newNode;
 
    //pridavam hranu z druheho prvku do prvniho
    newNode = createNode(src, val, edge);
    newNode->next = graph->adjLists[dest];
    graph->adjLists[dest] = newNode;
}
 
/*void deleteEdge(struct Graph* graph, int src, int dest, int val, int edge) {
    //pridavam hranu z prvniho prvku do druheho
    struct node* newNode = graph->adjLists[src];//createNode(dest, val, edge);
 
    newNode->next = graph->adjLists[src];
    graph->adjLists[src] = newNode;
 
    //pridavam hranu z druheho prvku do prvniho
    newNode = createNode(src, val, edge);
    newNode->next = graph->adjLists[dest];
    graph->adjLists[dest] = newNode;
}*/
 
 
//vytvorim adjacency List o "elements" prvcich
struct Graph* createGraph(int elements) {
    struct Graph* graph = malloc(sizeof(struct Graph));
    graph->numElements = elements; 
    graph->adjLists = malloc(elements * sizeof(struct node*)); 
    for (int i = 0; i < elements; i++)
        graph->adjLists[i] = NULL; // prozatim na NULL
    return graph;
}
 
//prohleda mi adjacency List do sirky a vrati sokety
int bfs(int v, struct Graph* graph) {
	memcpy(help_visited,visited,sizeof(char)*all_servers); // VZDY PREPISU NOVE
	int front = 0; rear = 0;
 	if (bfs_count == 0) {
 		for (int i=0; i<all_servers; i++) { //resi mi spravne levo a pravo, jinak byly problemy s 0
 			queue[i] = -1;
 		} 
 		bfs_count =1;
 	}		
 	else { 
 		for (int i=0; i<all_servers; i++) {
 			queue[i] = -1;
 		//	used[i] = 0;
 		//	visited[i] = 0;
 		}  	
 	}
    help_visited[v] = 0;
    //used[v] = 1;
    queue[rear] = v;
 
    rear++; //konec
    while (rear != front) {//dokud fronta neni plna/prazdna
    	int u = queue[front]; //prvni prvek, ktery byl zvolen
//    	fprintf(stderr,"%d\n", u);
       // used[u] = 1;
        front++;
     //   printf("juch");
        struct node* temp = graph->adjLists[u];   
 
        while (temp)	{//dokud prvek s necim sousedi
         //  if(!used[temp->value]) { //pokud uz jsem z nej neprohledavala
           		if (help_visited[temp->value]) {
           			if(keys[temp->value] == 1) {
           				return temp->value;
           			}
           			queue[rear] = temp->value;
           			rear++;
           			help_visited[temp->value] = 0; 
 
 
           		}
           		/*else { //tohle mi vubec nenastane
            		done = 1;
            		if (keys[temp->value] == '1') {
            			done = 1;
            		}
            		return;
  				}	*/
 
            temp = temp->next;
		}
    }
	return -1;
}
/*void freeGraph(struct Graph* graph, int m) {
    int i;
    for (i = 0; i < m; ++i) {
        free(graph->adjLists[i]);
    }
    //free(a);
    free(graph);
} */
 
 
int main(int argc, char *argv[])
{
	clock_t start = clock(); 
 
//	int connections;
	//int first_connected;
	//int second_connected;
 
 
 
 
 
int key_servers; // cislovani serveru je od 0
int label1;
int label2;
int transfer_time;
int key_serv;
int final_price = 0;
 
 
	if (scanf("%d %d", &all_servers, &key_servers) != 2) {
		 printf("Input is wrong!");
		 return 2;
	}
	struct Graph* graph = createGraph(all_servers);
	visited = calloc(all_servers, sizeof(unsigned char));
 
	help_visited = calloc(all_servers, sizeof(unsigned char));
 
	neighbour_counter = calloc(all_servers, sizeof(int));
	opposite_neigh = calloc(all_servers, sizeof(int));
	used = calloc(all_servers, sizeof(unsigned char));
	queue = calloc(all_servers, sizeof(int));
	keys = calloc(all_servers, sizeof(unsigned char));
	//side = calloc(all_servers, sizeof(unsigned char));
	zapocitat = calloc(all_servers, sizeof(unsigned char));
 
 
	//plnim adj. graf
	for (int i=0; i< all_servers; i++) {
		scanf("%d %d %d", &label1, &label2, &transfer_time);
		addEdge(graph, label1, label2, transfer_time, i);
		neighbour_counter[label1]++;
		neighbour_counter[label2]++;
	}	
 
	for (int i=0; i<key_servers; i++) {
		scanf("%d", &key_serv); //pak jeste neco budu muset delat s tim polem
		//printf("key: %d\n", key_serv);
		keys[key_serv] = 1;
		//bfs(key_serv, graph); //TO BFS JAKO TAKOVY FUNGUJE, JEN JA TO DIVNE PROCHAZIM
	}
 
 
 
	for (int i=0; i<all_servers; i++) {
				//zacnu od nej prochazet po rozcesti - po nekoho, kdo ma 3 sousedy, jestli to spravne chapu...
		if (neighbour_counter[i] == 1) {
			int list_start = i;
			int branch_counter = 0;
			int zacinam_pocitat = 0;
			while (1) {
 
				struct node* temp = graph->adjLists[list_start];
					while (visited[temp->value]) {
						temp = temp->next;
					}
					if (zacinam_pocitat == 0) { 
						if ((keys[list_start] == 1) || (zapocitat[list_start] == 1)) { //OVERIM, JESTLI NEJEDU Z NODU S MEZEROU
							zacinam_pocitat = 1;
						}
					}
					if (zacinam_pocitat == 1) {
					branch_counter = branch_counter + temp->price;
					}
 
					//printf("value:%d price:%d\n branch_counter:%d\n", temp->value, temp->price, branch_counter);
					neighbour_counter[list_start] --;
				//	printf("neigbour_counter: %d",neighbour_counter[temp->value]);
					neighbour_counter[temp->value] --;
//zkouska noveho					
					opposite_neigh[list_start]++;
					opposite_neigh[temp->value]++;
 
 
 
					visited[list_start] = 1; //ANO, SPRAVNE MUSIM OZNACIT JENOM LIST_START
					if (neighbour_counter[temp->value] == 1) { //tj chci pokracovat dal - ale jeste predtim potrebuju nejak odebrat tamtu hranu
						list_start = temp->value;
 
						if (zacinam_pocitat == 1) {
							zapocitat[temp->value] = 1;
						}
 
					}
					else {
//						printf("%d\n", branch_counter);
						final_price = final_price + branch_counter;
						//tady koncim - prirazuji USED
						if (zacinam_pocitat == 1) {
							zapocitat[temp->value] = 1;
						}
						//NOVE ZMENENO - CHCI, ABY USED BYLO SKUTECNE JEN TO, KAM NECO DOSLO..., s puby to nic neudelalo
						if (zacinam_pocitat == 1) {
							used[temp->value] = 1; //mohlo to i pomoct
						}
 
						break;
					}
					//for (int q=0;q<
 
			}
			//i=0;
 
		}
	}
//	printf("hupky");
	final_price = final_price*2;
//	fprintf(stderr,"%d\n", final_price);
 
	for (int i=0; i<all_servers; i++) {	//ZAS KDYBY TO NEFUNGOVALO, JAK TO, ZE TOHLE VSE JE 2?
		 if (neighbour_counter[i] == 1) {
		 //	printf("VITEZSTVI!");
		 //	printf("%d", neighbour_counter[i]);
		 }
	}
 
 
 
	int cycle_price = 0;
	int prvni = -1;
	int prvni_smycka = 0;
	int cycle_vertex = 0;
	int value2;
	int value2_price = 0;
 
	int cur_component=0;
	int biggest_component=0;
	int done_price = 0;
 
	int stav_8 = 0;
 
	//SNAZIM SE PREDEJIT TOMU, ZE VSE JE V JEDNE VETVI - TIM PADEM, KDYZ USED JE JEN JEDEN
	int used_counter = 0;	
 
	//nove reseni 10
	int my_used_counter = 0;
	int the_used_node = 0;
	for (int i=0; i<all_servers;i++) {
		if ((used[i] !=0) && (neighbour_counter[i] !=0)) {
			my_used_counter++;
			//bfs(i, graph);
			//return 0;
			the_used_node = i;
			//printf("juchuuuu\n");
		}
		if (my_used_counter >= 2) {
			break;
		}
	}
 
 
	if ((my_used_counter == 1) && (keys[the_used_node] == 1)) {
		//nemusim nic delat, uz to mam zpocteno
		printf("%d\n", final_price);
		return 0;
	}
 
	else if (my_used_counter == 1) { //vsechny jsou ze stejneho, a nekonci to keyem, takze budu muset neco odecist //ZACATEK
		//printf("hup");
 
		int opposite_price = 0;
		//int counter_mine = 0;
while (1) {
		struct node* temp_op = graph->adjLists[the_used_node];
		//if (counter_mine
 
		int one_side_key = -1;
		int other_side_key = -1;
		int little_price = 0;
 
		//NOVE
/*		fprintf(stderr,"visited\n");
		printmatrixchar(all_servers, visited);
		fprintf(stderr,"\n");
		fprintf(stderr,"opposite_neigh\n");
		printmatrixint(all_servers,opposite_neigh); */
 
 
		//MA TO BYT VEVNITR V CYKLU? //SEM MI TO VUBEC NESKOCI - ROZVETVUJE SE TO OD 1.
		if (opposite_neigh[the_used_node] == 1) { //kdyz jdu jen 1 smerem, jsem ok a jdu dokud nenarazim na key
					while((!visited[temp_op->value])) {
		temp_op = temp_op->next;
		}
 
//		fprintf(stderr,"Jsem zpet v teto podmince, spravne");
 
 
 
//			fprintf(stderr,"jsem v 1");
			opposite_price = opposite_price+temp_op->price;	//NEMAM TO NAHODOU PRICIST UZ NAHORE? - MYSLIM, ZE NE
			//pri														
			if (keys[temp_op->value] == 1) {
			//	printf("huraaaaa"); - tak jo, na muj pidiprikladek to funguje...
				//tady to skoncim, dosla jsem ke klici, mam vystarano
				final_price = final_price - (opposite_price*2);
 
				printf("%d\n", final_price);
				return 0;
			}
			else {
				//bohuzel, musim pokracovat - presunu node a jedu znovu
				the_used_node = temp_op->value;
				//JE PRO ME DULEZITE VISITED, MELA BYCH HO PREPSAT:
				visited[temp_op->value] = 0;															//POZOR NA TO VISITED!, TAKY BYCH MELA ASI SNIZIT POCET SOUSEDU, NE?
				opposite_neigh[the_used_node] --;
				continue;						//ZATIM NEMAM CYKLUS, POTOM ODKOMENTOVAT
			}
		}
 
 //CHYBA JE TADY V TOM ELSE!!!
		else { //kdyz muj node, ve kterem se nachazim, ma vice, nez 1 spojeni - na zacatku mam vzdy najite relevantni, v probehu uz je musim dohledavat!
		//	printf("vice");
			for (int i=0; i<opposite_neigh[the_used_node];i++) {
//				fprintf(stderr,"vice");
//				fprintf(stderr,"I index: %d\n", i);
 
//					fprintf(stderr,"CUR NODE: %d", the_used_node);
				//	fprintf(stderr,"vsited in 2: %d", visited[2]); //OCITLA JSEM SE TU MOCKRAT
					while((!visited[temp_op->value])) { //potrebuji to donacist
//						fprintf(stderr,"vysited in %d: %d\n", temp_op->value, visited[temp_op->value]);
					//	fprintf(stderr,"%d\n", temp_op->value);
//						fprintf(stderr,"fakt se mi to kousne tady");
						temp_op = temp_op->next;
//						fprintf(stderr,"neskoci_to sem");
					}
 
//				fprintf(stderr,"vyskocilo to");
 
				if (keys[temp_op->value] == 1) {
				//ukoncim to bez pricteni ceny
					final_price = final_price - (opposite_price*2);
					printf("%d\n", final_price);
					return 0;
				}
 
 
				//bfs from childu... kdyz najdu key, skoncim to a reknu, ze je TO TENHLE TEMP->VALUE a ulozim si one_side_key; - protoze 
//				fprintf(stderr,"temp: %d\n", temp_op->value);
				int ret = bfs(temp_op->value, graph);
 
//				fprintf(stderr, "\ntemp_op: %d RET: %d\n", temp_op->value,ret);
 
				if (ret != -1) {
//					fprintf(stderr,"juch");
					if (one_side_key == -1) {
//						fprintf(stderr,"jsem tady ikdyz tu nemam byt");
						one_side_key = temp_op->value; //je mi jedno, jake je to key
						little_price = temp_op->price; //pricetla jsem si cenu toho, kam budu pokracovat //nemam vyresene to pokracovani dal
//						fprintf(stderr,"%d", little_price);
					}
					else {
						//ukoncuji bez pricitani
//						fprintf(stderr,"tady to hrapuje");
						final_price = final_price - (opposite_price*2);
						printf("%d\n", final_price);
						return 0;
						//RETURN
					}
				}
 
				//POKUD ONE SIDE KEY NENI -1, A JA MAM POZITIVNI SHODU, UKONCUJI TO... VRACIM VYPOCET CENY
 
 
				//PROHLASUJI TEMP ZA NAVSTIVENY - hodnoty mam ted obracene
				visited[temp_op->value] = 0; //CHAPU TO SPRAVNE, ZE TAM MAM PAK VSUDE NULY A BEHAM DOKOLECKA?
 
 
				//tady to presunu na dalsi temp, pokud uz to neprobehlo vsechny, co melo
				if (i == opposite_neigh[the_used_node]-1) { //POKUD TO DOBEHLO DO KONCE A NASLO TO POUZE JEDEN KEY SERVER, JINAK BY TO SPRAVNE MELO SKONCIT NA TAMTEN RETURN
//					fprintf(stderr,"\nes\n");
					//POUZE TADY POKRACUJU - STACI, KDYZ TO ODECTU TADY? - MOZNA, KDYZ UZ SE NIKDY NEPODIVAM NAD TO NAD TIM, TAK BY TO STACIT MOHLO, TAMTO MAM OZNACENY JAKO VISITED, TAK BY TO TAM SNAD NEMUSELO LEZT...
					the_used_node = one_side_key;
					opposite_price = opposite_price + little_price; //little price je cena te cesty, kdyz poprve narazim do nejake vetve s keyem, v te dbe jeste nevim, jestli v jinych vetvich na ne nenarazim tez...
					//nove
					opposite_neigh[the_used_node]--;
					break; //KONCIM NE? MUSIM ZKONCIT, ALE NEVIM, PROC BY MI TO CHTELO ZNOVA SKAKAT DO TOHO CYKLU?
 
 
 
 
					//ZKOUSIM ODSTRANIT TEN SPOJ V OPPOSITE NEIGH - PRECI JEN, NEKDE BYCH HO MELA ODTSRANOVAT
 
					//opposite_price = opposite_price+little_price;
 
					//a zaroven potrebuji pricist opposite cenu - vse probehlo dobre a ja pokracuji dal
				} 
 
			/*	else if (i<opposite_neigh[the_used_node]-1) {
					printf("\nno\n");
 
					printf("%d\n", temp_op->value);
				}*/
 
 
	} //for
		}
} //while
	} //KONEC
 
 
 
	for (int i=0; i<all_servers;i++) {
		if((neighbour_counter[i] != 0) && (used[i] != 0))  { //tvari se to, ze je tam vzdycky aspon 1 vetev, kdyztak pridej podminku, tim padem vzdycky bezim od used
			cycle_vertex = i;
			used_counter++; //TOU PODMINKOU VYLOUCIM, - MAM TAM SPOUSTU USU, ALE ZAJIMAJ ME JEN TY V KRUHU
			//MELO BY BYT JEDNO, JESTLI TO BEZIM OD 1. NEBO DRUHEHO NALEZENEHO, NE?
			if (used_counter == 2) {
		//	printf("cycle: %d\n", cycle_vertex); 
				break;
			}
		//	return 0;
		}
		//SNAHA O OSETRENI, KDYZ VE VETVICH NENI ZADNY KLICOVY SERVER - ABY TO OD NECEHO ZACLO BEZET
		if ((i==all_servers-1) && (used_counter == 0)) { //tzn. ze z zadne vetve nic neprislo, ne?  //SEM BY MI TO MELO SKOCIT POUZE, POKUD JE TO NULA
			for (int q=0;q<all_servers;q++) {
				if ((neighbour_counter[q] != 0) && (keys[q] == 1)) { //chci bezet od klice - komponenty ted nedelam pomoci used/neused, ale podle klice
					cycle_vertex = q;
					stav_8 = 1;
 
					break;
 
				}
			}
		}
	}
 
	if (used_counter == 1) {
		printf("%d\n", final_price);
		return 0;
	}
 
	struct node* temp2 = graph->adjLists[cycle_vertex];
	while((visited[temp2->value])) {
		temp2 = temp2->next;
	}
//	printf("value1: %d", temp2->value);
	temp2 = temp2->next;
	while((visited[temp2->value])) {
		temp2 = temp2->next;
	}
	value2 = temp2->value;
	value2_price = temp2->price;
//	printf("value2: %d", temp2->value);
 
	while (1) {
		if (visited[cycle_vertex] != 0) {
			break;
		}
		struct node* temp = graph->adjLists[cycle_vertex];
//		printf("cycle v: %d\n",cycle_vertex);
		if (cycle_vertex == value2) {
			//PRICTU TU POSLEDNI HRANU - PRICTU VZDY, KDYZ JDU VZDY OD USED
			cur_component = cur_component+value2_price;
//			printf("\ncur:comp: %d\n", cur_component);
			break;
		}
		while((visited[temp->value])) { //likviduji predchozi spoje
			temp = temp->next;
		}
		cycle_price = cycle_price+temp->price;
		cur_component = cur_component + temp->price;
		if (cur_component>biggest_component) {
			biggest_component = cur_component;
		}
		if (stav_8 == 0) {
			if (used[temp->value] == 1) { //prerusuji komponentu a zacinam novou
				//printf("\ncur:comp: %d\n", cur_component);
				cur_component = 0;
			}
		}
		if (stav_8 != 0) {
			if (keys[temp->value] == 1) {
				cur_component = 0;
			}
		}
//		printf("%d\n", cycle_price);
		visited[cycle_vertex] = 1;
		cycle_vertex = temp->value;
	} 
	cycle_price = cycle_price+value2_price;
	//fprintf(stderr, "FINAL CYCLE PRICE> %d\n", cycle_price);
 
 
	if (cur_component>biggest_component) {
		biggest_component = cur_component;
	}
 
 
	//zkousim ostetrit 8 - TENHLE VYPOCET ASI NEMUZU POUZIT :/
/*	if (final_price == 0) {
		done_price = cycle_price - biggest_component*2;
	}*/
 
//	printf("biggest_compo: %d\n", biggest_component);
	if ((biggest_component*2) > cycle_price) {
		//delam prvni vypocet
		done_price = final_price + cycle_price - ((biggest_component*2)-cycle_price);
	}
	else {
		//delam druhy vypocet - prictu cely cyklus
//		printf("nastava");
		done_price = final_price + cycle_price;
 
	}
	printf("%d\n", done_price);
	//return 0;
 
 
/*	for (int q=0; q<key_servers; q++) {
		if (neigbour_counter[q] == key_servers-1) {
			printf("%d ", neigbour_counter[q]);
		}
	}*/
/*
	for (int i=1; i<nodes;i++) {
		if (done == 1) {
			break;
		}
		int neigbour_counter = 0;
		int wrong = 0;
		int once = 0;
		int neigbour_one = 0;
		int neigbour_two = 0;
		struct node* temp = graph->adjLists[i];  
		    while (temp)
		    {
		    	once = 1;
		    	if (neigbour_counter == 0) {
		    		neigbour_one = temp->value;
		    	}
		    	else {
		    		neigbour_two = temp->value;
		    	}
		    	if (neigbour_counter >= 2) { //zkousim, jestli ma presne sousedy
		    	 	wrong = 1;
		    		break;}
		    	neigbour_counter++;
		    	temp = temp->next;
		    }
	    if (neigbour_two == 0) {wrong = 1;}
	    if (wrong != 1) { //zkousim, zda sousedi maji stejny pocet sousedu
	    	int n1 = 0;
	    	int n2 = 0;
	    	struct node* neigbour1 = graph->adjLists[neigbour_one];
	    	struct node* neigbour2 = graph->adjLists[neigbour_two];
 
	    	while (neigbour1) {
	    		n1++;
	    		neigbour1 = neigbour1->next;
	    	}
	    	while (neigbour2) {
	    		n2++;
	    		neigbour2 = neigbour2->next;
	    		if (n2>n1) {
	    			wrong = 1;
	    			break;
	    		}
	    	}
	    	if ((n1 == n2) && (wrong == 0) && (once == 1)) {
	    		//mozny soket, zacnu z nej bfs
	    		bfs(i, graph);
	    	}  	
	    }
	}
 
	free(visited);
	free(used);
	free(queue);
	free(side);
	free(done_socket);
 
*/
	//free(graph);
  clock_t end = clock();
    float seconds = (float)(end - start) / CLOCKS_PER_SEC;
//    printf("\n%f\n", seconds);
 
//	freeGraph(graph, all_servers);
	free(help_visited);
	free(visited);
	free(used);
	free(queue);
	free(neighbour_counter);
	free(opposite_neigh);
	free(zapocitat);
	return 0;
}

3. nejrychlejší v C/C++

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
 
typedef struct Node {
    int hodnota;
    int cena;
    struct Node* next;
} Node_t;
 
typedef struct PomocnaPole {
    int* poleSousedu;
    int* uzProjite;
    bool* byvalaKrizovatka;
    int* poleCenUzlu;
    int* sumaServeruVNodech;
} pomoc_t;
 
typedef struct Pole {
    struct Node *pocatekPole;
}  Pole_t;
 
typedef struct Graf {
    int pocetUzlu;
    struct Pole* pole;
} Grafik_t;
 
 
 
Grafik_t* udelejGrafa (int pocetUzlu) {
    Grafik_t* Graf = (Grafik_t*) malloc (1 * sizeof(Grafik_t));
    Graf->pocetUzlu = pocetUzlu;
    Graf->pole = (Pole_t*) malloc (pocetUzlu * sizeof(Pole_t));
    int i = 0;
    while (i < pocetUzlu) {
        Graf->pole[i].pocatekPole = NULL;
        i = i + 1;
    }
    return Graf;
}
 
pomoc_t* pomocPole;
 
int najdiSousedyProsim (int i, Grafik_t* Graf) {
    int sum = 0;
    Node_t *uzel = Graf->pole[i].pocatekPole;
    while (uzel != NULL) {
      //  if (pomocPole->uzProjite[uzel->hodnota]<=0) {
            sum++;
       // }
 
        uzel = uzel->next;
    }
    return sum;
}
 
void pridejUzlik (Grafik_t* Graf, int uzel1, int uzel2, int cena, int kolik) {
    Node_t* novyUzel = (Node_t*) malloc (1 * sizeof(Node_t));
    Node_t* novyUzel2 = (Node_t*) malloc (1 * sizeof(Node_t));
 
    novyUzel->hodnota = uzel2;
    novyUzel->cena = cena;
    novyUzel2->hodnota = uzel1;
    novyUzel2->cena = cena;
 
    novyUzel->next = Graf->pole[uzel1].pocatekPole;
    Graf->pole[uzel1].pocatekPole = novyUzel;
 
    novyUzel2->next = Graf->pole[uzel2].pocatekPole;
    Graf->pole[uzel2].pocatekPole = novyUzel2;
}
 
unsigned char* KS;
int numberKS = 0;
bool cenaJe = 0;
int kruznice = -13, sumaKSveVetvicce = 0;
int celkovaCena = 0, cenaKolem = 0;
char prvni = 1;
int nejCenaKruzCesty = 0, cenaZatimSpoctena = 0;
int soucetVetvi = 0;
 
 
int main () {
    int numberOfNodes, numberOfKS;
    scanf("%d %d", &numberOfNodes, &numberOfKS);
 
     pomocPole = (pomoc_t*) malloc(1 * sizeof(pomoc_t));
 
    // memsetovat a malloc
    KS = (unsigned char*) malloc (sizeof(unsigned char)*  numberOfNodes);
    memset( KS, 0, sizeof( KS));
    pomocPole->poleSousedu = (int*) malloc (sizeof(int)*  numberOfNodes);
    memset( pomocPole->poleSousedu, 0, sizeof(pomocPole->poleSousedu));
    pomocPole->byvalaKrizovatka = (bool*) malloc (sizeof(bool)*  numberOfNodes);
    memset(pomocPole->byvalaKrizovatka, 0, sizeof(pomocPole->byvalaKrizovatka));
 
 
    Grafik_t* Graf = udelejGrafa (numberOfNodes);
 
    int prvniN, druhy, cena;
    for (int n = 0; n < numberOfNodes; n++) {
        scanf("%d %d %d", &prvniN, &druhy, &cena);
        pridejUzlik (Graf, prvniN, druhy, cena, n);
        pomocPole->poleSousedu[prvniN]++;
        pomocPole->poleSousedu[druhy]++;
    }
    int pozice;
    for (int i = 0; i < numberOfKS; i++) {
        scanf("%i", &pozice);
        KS[pozice] = 1;
    }
 
    pomocPole->uzProjite = (int*) malloc (sizeof(int)*  numberOfNodes);
    memset(pomocPole->uzProjite, 0, sizeof(pomocPole->uzProjite));
    pomocPole->poleCenUzlu = (int*) malloc (sizeof(int) * numberOfNodes);
 
    for (int i = 0; i < numberOfNodes; i++) {
        pomocPole->poleCenUzlu[i] = 0;
    }
 
    pomocPole->sumaServeruVNodech = (int*) malloc (sizeof(int)*  numberOfNodes);
    memset(pomocPole->sumaServeruVNodech, 0, sizeof(pomocPole->sumaServeruVNodech));
 
 
    for (int k = 0; k < numberOfNodes; k++) {
 
        if (najdiSousedyProsim(k, Graf) == 1) {
            sumaKSveVetvicce = 0;
            pomocPole->uzProjite[k]=1;
            int prohledavanyUzlik = Graf->pole[k].pocatekPole->hodnota;
            bool zacniPocitatCenu = false;
            int prubeznaSumaCeny = 0;
 
            if (KS[k] == 1) { // list je KS
                zacniPocitatCenu = true;
                sumaKSveVetvicce++;
                prubeznaSumaCeny += Graf->pole[k].pocatekPole->cena;
            }
 
            for (int ba = 0; ba < numberOfNodes; ba++) {
 
                if (pomocPole->poleSousedu[prohledavanyUzlik] != 2){
                    break;
                }
                pomocPole->uzProjite[prohledavanyUzlik] = 1;
 
                if (pomocPole->byvalaKrizovatka[prohledavanyUzlik] == true || KS[prohledavanyUzlik] == 1) {
                    prubeznaSumaCeny = prubeznaSumaCeny + pomocPole->poleCenUzlu[prohledavanyUzlik];
                    zacniPocitatCenu = true;
                    sumaKSveVetvicce = sumaKSveVetvicce + (pomocPole->byvalaKrizovatka[prohledavanyUzlik] == true ? pomocPole->sumaServeruVNodech[prohledavanyUzlik]: 1);
                }
 
                if (sumaKSveVetvicce == numberOfKS) {
                    printf("%d", prubeznaSumaCeny * 2);
                    return 0;
                }
 
                Node_t *soucasnyUzlik = Graf->pole[prohledavanyUzlik].pocatekPole;
 
                for (int ble = 0; ble < numberOfNodes; ble++) {
                    if (pomocPole->uzProjite[soucasnyUzlik->hodnota] != 1) {
                        break;
                    }
                    soucasnyUzlik = soucasnyUzlik->next;
                    ble=0;
                }
                prubeznaSumaCeny = prubeznaSumaCeny + (zacniPocitatCenu == true ? soucasnyUzlik->cena : 0);
                prohledavanyUzlik = soucasnyUzlik->hodnota;
                ba=0;
            }
 
            pomocPole->byvalaKrizovatka[prohledavanyUzlik] = prubeznaSumaCeny > 0 ? true : pomocPole->byvalaKrizovatka[prohledavanyUzlik];
 
            pomocPole->poleSousedu[prohledavanyUzlik]--;
            pomocPole->poleCenUzlu[prohledavanyUzlik] = pomocPole->poleCenUzlu[prohledavanyUzlik] + prubeznaSumaCeny;
            pomocPole->sumaServeruVNodech[prohledavanyUzlik] = pomocPole->sumaServeruVNodech[prohledavanyUzlik] + sumaKSveVetvicce;
 
            // do kruznice nendu
            if (pomocPole->sumaServeruVNodech[prohledavanyUzlik] == numberOfKS) {
                int resultik0 = pomocPole->poleCenUzlu[prohledavanyUzlik] + pomocPole->poleCenUzlu[prohledavanyUzlik];
                printf("%ld", resultik0);
                return 0;
            }
 
            if (zacniPocitatCenu == true){
                kruznice = prohledavanyUzlik;
            }
        }
    }
 
    //spocti cenu loopu
    if (kruznice == -13){ // kdyz nebyla nastavena kruznice
        for (int i = 0; i < numberOfNodes; i++) {
            if (KS[i] == 1){   // nastav kruznici na key server
                kruznice=i;
            }
        }
    }
 
    int pocatekCesty = kruznice;
    pomocPole->uzProjite[kruznice] = 13;
 
    //projdem kruznici
    for (int i = 0; i <= numberOfNodes; i++) {
 
        Node_t *prochazeny = Graf->pole[pocatekCesty].pocatekPole;
 
        for (int y = 0; y <= numberOfNodes; y++) {
            if(prochazeny->hodnota >numberOfNodes || prochazeny->hodnota < 0){
                //printf("sakra");
            }
            if (pomocPole->uzProjite[prochazeny->hodnota] <= 0){
                break;
            }
            if (pomocPole->uzProjite[prochazeny->hodnota]> 7 && prvni == 0){
 
                cenaKolem = cenaKolem + prochazeny->cena;
                cenaZatimSpoctena = cenaZatimSpoctena + prochazeny->cena;
 
                nejCenaKruzCesty = nejCenaKruzCesty < cenaZatimSpoctena ? cenaZatimSpoctena : nejCenaKruzCesty;
 
                soucetVetvi = soucetVetvi + pomocPole->poleCenUzlu[prochazeny->hodnota];
 
                if (cenaKolem < (cenaKolem-nejCenaKruzCesty) * 2){
                    long int resultik = cenaKolem + soucetVetvi + soucetVetvi;
                    printf("%ld", resultik);
                } else {
                    long int resultik2 = soucetVetvi + soucetVetvi + 2 * (cenaKolem- nejCenaKruzCesty);
                    printf("%ld", resultik2);
                }
                return 0;
            }
            prochazeny = prochazeny->next;
        }
 
        cenaKolem += prochazeny->cena;
        cenaZatimSpoctena += prochazeny->cena;
 
        prvni = prvni == 1 ? -13 : 0;
        pomocPole->uzProjite[pocatekCesty] = pomocPole->uzProjite[pocatekCesty] + 1;
        pocatekCesty = prochazeny->hodnota;
        soucetVetvi = soucetVetvi + pomocPole->poleCenUzlu[pocatekCesty];
 
        int temp = nejCenaKruzCesty;
 
        nejCenaKruzCesty = (KS[pocatekCesty] > 0 || pomocPole->poleCenUzlu[pocatekCesty]) > 0? (nejCenaKruzCesty < cenaZatimSpoctena ? cenaZatimSpoctena : nejCenaKruzCesty) : nejCenaKruzCesty;
        nejCenaKruzCesty = pomocPole->poleCenUzlu[pocatekCesty] > 0 ? (nejCenaKruzCesty = nejCenaKruzCesty < cenaZatimSpoctena ? cenaZatimSpoctena : nejCenaKruzCesty) : nejCenaKruzCesty;
 
        if (nejCenaKruzCesty != temp){
            cenaZatimSpoctena = 0;
        }
        if (pomocPole->poleCenUzlu[pocatekCesty] > 0) {
            nejCenaKruzCesty = nejCenaKruzCesty < cenaZatimSpoctena ? cenaZatimSpoctena : nejCenaKruzCesty;
            cenaZatimSpoctena = 0;
        }
        i = 0;
    }
}

1. nejrychlejší v Javě

package alg;
 
public class Spojeni {
    int kam;
    int cena;
    Spojeni paroveSpojeni;
 
    public Spojeni(int kam, int cena) {
        this.kam = kam;
        this.cena = cena;
    }
}
 
package alg;
 
import java.io.IOException;
import java.util.ArrayList;
 
 
public class Main {
    private InputReader ir = new InputReader();
    private int N;
    private int K;
 
    /* NODE */
    private boolean[] jeDulezity;
    private boolean[] jeNodeNavstiven;
    private boolean[] jeNodeKlic;   
    private int[] aktualniCena;
    private int celkovaCenaVetvi = 0;
    private int celkovaCenaCyklu = 0; 
    private ArrayList<Spojeni>[] spojeni;
 
    /* CYKLUS */
    private int startovniNode;
    private int pocetNoduVCyklu = 0;
 
 
    public void nactiVstup() throws IOException{
        N = ir.nextInt();
        K = ir.nextInt();
        aktualniCena = new int[N];
        jeNodeNavstiven = new boolean[N];
        jeNodeKlic = new boolean[N];
        jeDulezity = new boolean[N];
        spojeni = new ArrayList[N];
 
        for (int i = 0; i < N; i++) {
            spojeni[i] = new ArrayList<>();
        }
 
        for (int i = 0; i < N; i++) {
            int levyNode = ir.nextInt();
            int pravyNode = ir.nextInt();
            int cenaSpojeni = ir.nextInt();
 
            Spojeni praveSpojeni = new Spojeni(pravyNode, cenaSpojeni);
            Spojeni leveSpojeni = new Spojeni(levyNode, cenaSpojeni);
 
            praveSpojeni.paroveSpojeni = leveSpojeni;
            leveSpojeni.paroveSpojeni = praveSpojeni;
 
            spojeni[levyNode].add(praveSpojeni);
            spojeni[pravyNode].add(leveSpojeni);
        }
 
        for (int i = 0; i < K; i++) {
            int klic = ir.nextInt();
            jeNodeKlic[klic] = true;
            jeDulezity[klic] = true;
        }
    }
 
    public boolean odstrihniVetve(){     
        boolean preruseniCyklu = true;
        int pocetKlicuVeVetvich = 0;
        while (preruseniCyklu) {
            preruseniCyklu = false;
            for (int i = 0; i < N; i++) {
                int index = i;
                while (!jeNodeNavstiven[index] && spojeni[index].size() == 1) {
                    preruseniCyklu = true;
                    jeNodeNavstiven[index] = true;
                    Spojeni noveSpojeni = spojeni[index].get(0);
                    if (jeNodeKlic[index]) {
                        pocetKlicuVeVetvich++;
                        if (K == 1000 && pocetKlicuVeVetvich == K) {
                            celkovaCenaVetvi = aktualniCena[index] * 2;
                            return false;
                        }
                    }
                    if (jeDulezity[index]) {
                        aktualniCena[noveSpojeni.kam] += aktualniCena[index] + noveSpojeni.cena;
                        jeDulezity[noveSpojeni.kam] = true;
                    }
                    spojeni[index].remove(noveSpojeni);
                    spojeni[noveSpojeni.kam].remove(noveSpojeni.paroveSpojeni);
                    index = noveSpojeni.kam;
                }
            }
        }
        for (int i = 0; i < N; i++) {
            if (spojeni[i].size() != 2) {
                continue;
            }
            if (jeDulezity[i]) {
                startovniNode = i;
                pocetNoduVCyklu++;
            }
            celkovaCenaVetvi += aktualniCena[i];
        }
        celkovaCenaVetvi *= 2;
        return true;
    }
 
    public void vyresKruznici(){
        int docasnaCena = 0;
        int[] docasnaCenaCyklu = new int[pocetNoduVCyklu + 1];
        int aktualniNode = startovniNode;
        int index = 1;
        int CenaCelehoCyklu;
        int posledniNode;
        int cena;
        while (spojeni[aktualniNode].size() > 0) {
            Spojeni noveSpojeni = spojeni[aktualniNode].get(0);
            docasnaCena += noveSpojeni.cena;
            if (jeDulezity[noveSpojeni.kam]) {
                docasnaCenaCyklu[index] = docasnaCena;
                index++;
            }
            spojeni[aktualniNode].remove(noveSpojeni);
            spojeni[noveSpojeni.kam].remove(noveSpojeni.paroveSpojeni);
            aktualniNode = noveSpojeni.kam;
        }
        CenaCelehoCyklu = docasnaCenaCyklu[pocetNoduVCyklu];
        celkovaCenaCyklu = docasnaCenaCyklu[pocetNoduVCyklu];
        for (int i = 0; i < pocetNoduVCyklu; i++) {
            posledniNode = (i + pocetNoduVCyklu - 1) % pocetNoduVCyklu;
            cena = docasnaCenaCyklu[posledniNode] - docasnaCenaCyklu[i];
            if (cena < 0) {
                cena += CenaCelehoCyklu;
            }
            cena *= 2;
            if (cena < celkovaCenaCyklu) {
                celkovaCenaCyklu = cena;
            }
        }
    }
    public void Vysledek() {
         System.out.println(celkovaCenaVetvi + celkovaCenaCyklu);
    }
 
    public static void main(String[] args) throws IOException {
        Main main = new Main();
        main.nactiVstup();
        if (main.odstrihniVetve()) {
            main.vyresKruznici();
        }
        main.Vysledek();    
    }
}

2. nejrychlejší v Javě

package alg;
 
public class Connection {
 
    int to, cost;
    Connection pairConnection;
 
    public Connection(int to, int cost) {
        this.to = to;
        this.cost = cost;
    }
}
 
package alg;
 
import java.io.IOException;
import java.util.ArrayList;
 
public class Main {
 
    private InputReader ir = new InputReader();
 
    private int N, K;
 
    //node replacement
    private boolean isUnvisited[];
    private boolean isKeyServer[];
    private boolean isImportant[];
    private int actualValue[];
 
    private ArrayList<Connection> connections[];
 
 
    private int sumOfBranches = 0, sumOfCircle = 0;
 
    //circle things
    private int startNode;
    private int numOfNeededCircleNodes = 0;
 
 
    public void loadData() throws IOException {
        N = ir.nextInt();
        K = ir.nextInt();
 
        isUnvisited = new boolean[N];
        isKeyServer = new boolean[N];
        isImportant = new boolean[N];
        actualValue = new int[N];
 
        connections = new ArrayList[N];
        for (int i = 0; i < N; i++) {
            connections[i] = new ArrayList<>();
            isUnvisited[i] = true;
        }
 
 
        for (int i = 0; i < N; i++) {
 
            int leftIndex = ir.nextInt();
            int rightIndex = ir.nextInt();
            int cost = ir.nextInt();
 
            Connection con1 = new Connection(rightIndex, cost);
            Connection con2 = new Connection(leftIndex, cost);
 
            con1.pairConnection = con2;
            con2.pairConnection = con1;
 
            connections[leftIndex].add(con1);
            connections[rightIndex].add(con2);
        }
 
        for (int i = 0; i < K; i++) {
            int index = ir.nextInt();
            isKeyServer[index] = true;
            isImportant[index] = true;
        }
 
    }
 
 
    public boolean cutBranches() {
 
        int numOfKeysInBranches = 0;
 
 
        boolean change = true;
 
        while (change) {
            change = false;
            for (int idx = 0; idx < N; idx++) {
                int i = idx;
                while (isUnvisited[i] && connections[i].size() == 1) {
                    change = true;
 
                    isUnvisited[i] = false;
 
                    Connection conn = connections[i].get(0);
 
                    if (isKeyServer[i]) {
                        numOfKeysInBranches++;
 
                        if (numOfKeysInBranches == K && K == 1000) {
                            sumOfBranches = actualValue[i] * 2;
                            return false;
                        }
 
                    }
 
                    if (isImportant[i]) {
                        actualValue[conn.to] += actualValue[i] + conn.cost;
                        isImportant[conn.to] = true;
                    }
 
                    connections[i].remove(conn);
                    connections[conn.to].remove(conn.pairConnection);
 
                    i = conn.to;
                }
            }
        }
 
        for (int i = 0; i < N; i++) {
 
            if (connections[i].size() != 2) {
                continue;
            }
 
            if (isImportant[i]) {
                startNode = i;
                numOfNeededCircleNodes++;
            }
            sumOfBranches += actualValue[i];
        }
        sumOfBranches *= 2;
        return true;
    }
 
 
    public void doCircle() {
 
        int tempSum = 0;
        int tempCircleSum[] = new int[numOfNeededCircleNodes + 1];
 
        int actNode = startNode;
        int neededIndex = 1;
        while (connections[actNode].size() > 0) {
 
            Connection conn = connections[actNode].get(0);
 
            tempSum += conn.cost;
            if (isImportant[conn.to]) {
                tempCircleSum[neededIndex] = tempSum;
                neededIndex++;
            }
 
            connections[actNode].remove(conn);
            connections[conn.to].remove(conn.pairConnection);
 
            actNode = conn.to;
        }
 
        int wholeCircle = tempCircleSum[numOfNeededCircleNodes];
        sumOfCircle = tempCircleSum[numOfNeededCircleNodes];
 
        //nyni vyuziju vysledky
        for (int i = 0; i < numOfNeededCircleNodes; i++) {
 
            int endIndex = (i + numOfNeededCircleNodes - 1) % numOfNeededCircleNodes;
            int cost = tempCircleSum[endIndex] - tempCircleSum[i];
            if (cost < 0) {
                cost += wholeCircle;
            }
            cost *= 2;
            if (cost < sumOfCircle) {
                sumOfCircle = cost;
            }
        }
    }
 
    public int computeFinalResult() {
        return sumOfBranches + sumOfCircle;
    }
 
    public static void main(String[] args) throws IOException {
        Main m = new Main();
 
        m.loadData();
        boolean ret = m.cutBranches();
        if (ret)
            m.doCircle();
        System.out.println(m.computeFinalResult());
 
    }
}

3. nejrychlejší v Javě

package alg;
 
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
 
/**
 *
 */
public class Main {
 
    private static final Scanner s = new Scanner(System.in);
    private static int nextInt() {
        return Integer.parseInt(s.next());
    }
 
    static class Reader {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;
 
        public Reader() {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }
 
        public Reader(String file_name) throws IOException {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }
 
        public String readLine() throws IOException {
            byte[] buf = new byte[64]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }
 
        public int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');
 
            if (neg) return -ret;
            return ret;
        }
 
        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }
 
        private byte read() throws IOException {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }
 
        public void close() throws IOException {
            if (din == null)
                return;
            din.close();
        }
    }
 
 
    private static class ConnectionArray {
 
        private Connection[] backing;
        private int used = 0;
 
        public ConnectionArray(int initialCapacity) {
            backing = new Connection[initialCapacity];
        }
 
        public void add(Connection num) {
            if (used == backing.length) {
                Connection[] bigger = new Connection[backing.length * 2];
                System.arraycopy(backing, 0, bigger, 0, used);
                backing = bigger;
            }
            backing[used++] = num;
        }
 
        public Connection get(int i) {
            return backing[i];
        }
 
        public boolean contains(Connection num) {
            for (int i = 0; i < used; i++) {
                if (backing[i] == num) return true;
            }
            return false;
        }
 
        public boolean remove(int node) {
            for (int i = 0; i < used; i++) {
                if (backing[i].node == node) {
                    backing[i] = backing[--used];
                    return true;
                }
            }
            return false;
        }
 
        public int size() {
            return used;
        }
 
        public void clear() {
            used = 0;
        }
    }
 
    private static class Connection {
        public final int node;
        public final int cost;
 
        public Connection(int node, int cost) {
            this.node = node;
            this.cost = cost;
        }
 
        @Override
        public int hashCode() {
            return node * 613 + cost * 809;
        }
 
        @Override
        public boolean equals(Object obj) {
            return obj != null && obj instanceof Connection && ((Connection) obj).node == node;
        }
    }
 
    private static TreeSet<Integer> keyServers = new TreeSet<>();
    private static final ArrayList<ConnectionArray> connections = new ArrayList<>();
 
    public static void main(String[] args) throws IOException {
 
        long timeSinceLastCheckpoint = System.currentTimeMillis();
 
        final Reader s = new Reader();
 
        final int serverCount = s.nextInt();
        final int keyServCount = s.nextInt();
 
        connections.ensureCapacity(serverCount);
        for (int i = 0; i < serverCount; i++) {
            connections.add(new ConnectionArray(70));
        }
 
        for (int i = 0; i < serverCount; i++) {
            final int nodeA = s.nextInt();
            final int nodeB = s.nextInt();
            final int edgeCost = s.nextInt();
 
            connections.get(nodeA).add(new Connection(nodeB, edgeCost));
            connections.get(nodeB).add(new Connection(nodeA, edgeCost));
        }
 
        for (int i = 0; i < keyServCount; i++) {
            final int keyServId = s.nextInt();
            keyServers.add(keyServId);
        }
 
        if (keyServers.size() <= 1) {
            System.out.println(0);
            return;
        }
 
        System.err.println("[" + (System.currentTimeMillis() - timeSinceLastCheckpoint) / 1000f + "s] Loaded"); timeSinceLastCheckpoint = System.currentTimeMillis();
 
        int treeCost = 0;
        int node;
        for (int i = 0; i < connections.size(); i++) {
            if (connections.get(i).size() != 1) continue;
            node = i;
            boolean keyServPath = false;
            while (connections.get(node).size() == 1) {
                final ConnectionArray cons = connections.get(node);
                final Connection c = connections.get(node).get(0);
                for (int j = 0; j < cons.size(); j++) if (cons.get(j).node == node) {
                    cons.remove(j);
                    break;
                }
 
                connections.get(c.node).remove(node);
                connections.get(node).clear();
 
                if (keyServers.remove(node)) keyServPath = true;
 
                if (keyServers.size() == 0) {
                    System.out.println(treeCost * 2);
                    System.err.println("[" + (System.currentTimeMillis() - timeSinceLastCheckpoint) / 1000f + "s] Tree cost: " + treeCost + ", no cycle"); timeSinceLastCheckpoint = System.currentTimeMillis();
                    return;
                }
                if (keyServPath) {
                    treeCost += c.cost;
                }
 
                node = c.node;
            }
            if (keyServPath) {
                keyServers.add(node);
            }
        }
 
        System.err.println("[" + (System.currentTimeMillis() - timeSinceLastCheckpoint) / 1000f + "s] Cycle isolated,  tree cost: " + treeCost); timeSinceLastCheckpoint = System.currentTimeMillis();
 
        int cycleNextNode, cycleLastNode;
        final int prices[] = new int[keyServers.size()];
        int priceI = 0;
        int edgeCost = 0;
        int fullCost = 0;
 
        for (int i = 0; i < connections.size(); i++) {
            if (connections.get(i).size() == 2 && keyServers.contains(i)) {
                cycleNextNode = i;
                cycleLastNode = connections.get(i).get(0).node;
 
                do {
                    final ConnectionArray c = connections.get(cycleNextNode);
                    final int next = c.get(0).node == cycleLastNode ? c.get(1).node : c.get(0).node;
                    edgeCost += c.get(0).node == cycleLastNode ? c.get(1).cost : c.get(0).cost;
                    cycleLastNode = cycleNextNode;
                    cycleNextNode = next;
 
                    if (keyServers.contains(cycleNextNode)) {
                        prices[priceI++] = edgeCost;
                        fullCost += edgeCost;
                        edgeCost = 0;
                    }
                } while (cycleNextNode != i);
                break;
            }
        }
 
        int bestCycleCost = fullCost;
        for (int price : prices) {
            if ((fullCost - price) * 2 < bestCycleCost) bestCycleCost = (fullCost - price) * 2;
        }
 
 
 
        System.err.println("[" + (System.currentTimeMillis() - timeSinceLastCheckpoint) / 1000f + "s] Inner cycle cost: " + bestCycleCost); timeSinceLastCheckpoint = System.currentTimeMillis();
        System.out.println(treeCost * 2 + bestCycleCost);
 
    }
}

courses/b4b33alg/cviceni/4_keyservers.txt · Last modified: 2018/09/24 15:06 (external edit)