#include #include #include #define MAX_N 100000 #define MAX_M 100000 int S[MAX_M+1]; // S[w] = 1, pokud jde poskládat množinu předmětů váhy w int last[MAX_M+1]; // poslední předmět přidaný do batohu před dosažením dané váhy int N, M; int deg[MAX_N][2]; // vstupní a výstupní stupeň vrcholu (počet přijatých a odeslaných dopisů) int W[MAX_N]; int gang[MAX_N]; // příslušnost ke gangu (0 nebo 1) int total_out, total_in; void read_input(void) { scanf("%d", &N); for (int i=0; i= 0; w--) { if (!S[w]) continue; int new_weight = w + W[i]; if (new_weight > M) continue; if (S[new_weight]) continue; S[new_weight] = 1; last[new_weight] = i; if (new_weight == M) { return 1; } } } return 0; } void reconstruct_gangs(void) { int cur = M; while (cur != 0) { //fprintf(stderr, "cur=%d last=%d w=%d\n", cur, last[cur], W[last[cur]]); gang[last[cur]] = 1; cur -= W[last[cur]]; } } int min(int a, int b) { if (a < b) return a; else return b; } // Vytvoř hrany odpovídací dopisům v jednom směru // from=0: směr A->B, from=1: směr B->A void reconstruct_edges(int from) { int to = !from; int send_i = 0; // index procházení odesílajícího gangu int recv_i = 0; // index procházení přijímajícího gangu while (1) { while (send_i < N && (gang[send_i] != from || deg[send_i][1] == 0)) send_i++; while (recv_i < N && (gang[recv_i] != to || deg[recv_i][0] == 0)) recv_i++; if (send_i >= N && recv_i >= N) break; if (send_i >= N || recv_i >= N) abort(); int max_edges = min(deg[send_i][1], deg[recv_i][0]); if (max_edges > 0) { printf("%d %d %d\n", send_i, recv_i, max_edges); deg[send_i][1] -= max_edges; deg[recv_i][0] -= max_edges; } } } int main() { read_input(); // Vyřešíme problém batohu if (!knapsack()) { fprintf(stderr, "Řešení neexistuje: nelze vyváženě rozdělt na gangy\n"); return 1; } reconstruct_gangs(); // Rozdělíme vrcholy do gangů podle řešení batohu reconstruct_edges(0); // Zrekonstruujeme dopisy A->B reconstruct_edges(1); // Zrekonstruujeme dopisy B->B->a return 0; }